Data engineer, Paris · Airflow · ClickHouse · dbt · Kubernetes · Snowflake · Databricks · Spark · AWS · GCPData engineer, Paris · Airflow · ClickHouse · dbt · Kubernetes · Snowflake · Databricks · Spark · AWS · GCP
CLICKHOUSE2026-08-12

Debugging Blocked ClickHouse DDL with ON CLUSTER

Tahirintsoa Mamitiana·3 min read

The symptom

A migration run was adding a column to a table replicated across three nodes, via ALTER TABLE ... ON CLUSTER. The query never finished on the client side: timeout after several minutes. Looking at the metrics, one of the three nodes showed a growing replication lag, and the others were silently waiting.

How ON CLUSTER works

When you run a DDL statement with ON CLUSTER <cluster_name>, ClickHouse doesn't execute it directly: it pushes an entry into a distributed task queue, stored in ClickHouse Keeper (or ZooKeeper depending on the configuration), under the path /clickhouse/task_queue/ddl (the exact path depends on the distributed_ddl.path config). Every node in the cluster watches this queue and executes the DDL locally as soon as it sees it, then marks its status (finished or error) in a sub-node dedicated to that host.

The node that initiated the query waits for all hosts in the cluster to confirm execution, up to distributed_ddl_task_timeout (180 seconds by default before ClickHouse 22.x, -1, meaning an infinite wait, in some older configurations we'd inherited). If even a single node never responds, the entire query stays blocked until the timeout, or indefinitely.

Where to look to diagnose it

Three places to check, in order:

-- 1. État de la tâche DDL elle-même : quels hosts ont répondu, lesquels pas
SELECT host, port, status, exception_code
FROM system.distributed_ddl_queue
WHERE entry = 'query-0000012345'
ORDER BY host;
-- 2. Le nœud "manquant" a-t-il du retard de réplication ?
SELECT database, table, replica_is_active, absolute_delay
FROM system.replicas
WHERE absolute_delay > 60
ORDER BY absolute_delay DESC;

And as a last resort, the ClickHouse Keeper logs (/var/log/clickhouse-keeper/clickhouse-keeper.log on our hosts) to check there's no quorum or connectivity issue between nodes: a Keeper that loses quorum silently blocks the entire coordination mechanism.

Cases we've hit

How to unblock it

  1. Identify the blocking node via system.distributed_ddl_queue (empty or missing status for that host).
  2. Check whether it's simply lagging or actually dead: system.replicas.replica_is_active and absolute_delay. If the node responds to normal queries, waiting is usually enough. The task will eventually be processed. If it's down, it needs to be restarted.
  3. If the node won't come back in time (extended outage, instance replacement), you can manually delete the task entry for that host in Keeper to unblock the other nodes. Use this only as a last resort, and only after confirming the schema on the remaining nodes is consistent, since it leaves the faulty node out of sync until it comes back (you'll need to replay the DDL on it manually, or let it resync via a DETACH/ATTACH of the table if the divergence is too large).
  4. Post-incident check: query system.distributed_ddl_queue on the entry in question to confirm every host shows status = 'Finished', and compare the table schema (DESCRIBE TABLE) across each node.

How to avoid it next time