NEW

Pulse 2025 Product Roundup: From Monitoring to AI-Native Control Plane

ClickHouse Client Timeout Errors: Causes and Fixes

Timeouts in ClickHouse are not a single knob. There are at least eight settings that influence whether a client stays connected long enough to receive its result, and they cover different layers: TCP keep-alive, application-level send/receive, HTTP framing, and query execution. Most "my query disconnects after N seconds" reports trace back to a mismatch between one of these limits and the actual time the query needs. This article maps the settings to the failure modes they cause.

The settings that matter

ClickHouse exposes timeouts at three layers. Knowing which layer fires first saves a lot of guessing.

Setting Layer What it controls
receive_timeout Server, per-connection Maximum idle time waiting to read from a client. Slow or stalled clients get disconnected.
send_timeout Server, per-connection Maximum idle time waiting to write to a client. Triggers if the client stops reading.
tcp_keep_alive_timeout TCP Application-level keep-alive interval. Stops middleboxes from dropping idle TCP sessions.
http_receive_timeout HTTP HTTP equivalent of receive_timeout.
http_send_timeout HTTP HTTP equivalent of send_timeout.
keep_alive_timeout HTTP 1.1 How long the server holds a keep-alive socket open between requests. Defaults to 10s in 23.12+, was 3s before.
http_connection_timeout HTTP outbound Timeout for ClickHouse connecting to other servers. Does not affect inbound clients.
http_headers_progress_interval_ms HTTP How often the server emits progress headers during long queries.
http_wait_end_of_query HTTP If set, the server waits for the query to finish before closing the HTTP response.
max_execution_time Query Maximum wall time for query execution. Different from connection timeouts.
sync_request_timeout Server Timeout for synchronous internal calls like Ping or TableStatus. Default 5 seconds.

The key distinction: max_execution_time controls how long a query may run on the server. The receive/send/keep-alive family controls whether the client connection survives that long. A query can finish inside max_execution_time and still fail if the HTTP keep-alive closed the socket first.

Failure mode: HTTP idle disconnect during long queries

Symptom: a query that takes 30 seconds returns successfully via clickhouse-client, but the same query over HTTP through a load balancer or JDBC driver dies after a few seconds with a broken pipe or read error.

Cause: between the time the server starts executing and the time it produces the first byte of output, the HTTP socket is idle. If keep_alive_timeout or an intermediate proxy idle limit is shorter than the query's pre-output phase, the socket gets torn down.

Fix: have the server send progress updates so the connection is never truly idle.

SET send_progress_in_http_headers = 1;
SET http_headers_progress_interval_ms = 10000;
SET http_wait_end_of_query = 1;

For JDBC, pass these through the URL:

jdbc:clickhouse://host:8123/db?custom_settings=send_progress_in_http_headers=1,http_headers_progress_interval_ms=10000

http_wait_end_of_query makes the server hold the response open until the query completes, which prevents premature closure when results are buffered or empty.

Failure mode: receive_timeout closes the connection

Symptom: a client streaming an INSERT or running a long query that produces no output for a while sees Read timeout or Connection reset by peer.

Cause: receive_timeout (default 300s) closes connections where the server is waiting on the client. If you are inserting a large batch with slow producer code, or the client process is paused, the server gives up.

Fix: increase the relevant timeouts. These must be set in the default user profile because they take effect at connection establishment, not mid-session.

In users.d/long_running.xml:

<clickhouse>
  <profiles>
    <default>
      <receive_timeout>3600</receive_timeout>
      <send_timeout>3600</send_timeout>
      <tcp_keep_alive_timeout>3600</tcp_keep_alive_timeout>
      <http_headers_progress_interval_ms>10000</http_headers_progress_interval_ms>
      <http_wait_end_of_query>1</http_wait_end_of_query>
    </default>
  </profiles>
</clickhouse>

Setting these per-query with SET is too late for the values that govern session establishment.

Failure mode: NAT or load balancer kills idle TCP

Symptom: connections that sit idle for several minutes between queries silently die, and the next query fails. This is common on AWS NLBs (350s idle timeout) and corporate firewalls.

Cause: the network device drops the TCP flow because it sees no traffic. The application-level keep_alive_timeout does not help here because keep-alive is between requests on the same socket, not while one is in flight.

Fix: enable TCP keep-alive so packets flow even during idle periods.

<tcp_keep_alive_timeout>60</tcp_keep_alive_timeout>

This makes ClickHouse emit TCP keep-alive probes at the specified interval. Set the value lower than the NAT or LB idle timeout.

Inspecting current values

To see what is actually in effect for the current session:

SELECT name, value, changed, description
FROM system.settings
WHERE name ILIKE '%timeout%' OR name ILIKE '%keep_alive%'
ORDER BY name;

changed = 1 means the value differs from the compiled default and was set via config or SET.

Common Pitfalls

  • Setting receive_timeout with SET after the connection is open. The session already has its values; raise them in the default profile or pass via session parameters at connect time.
  • Tuning only max_execution_time to fix a disconnect. Execution time is unrelated to whether the HTTP socket stays alive.
  • Forgetting that HTTP clients sit behind load balancers with their own idle timeouts. Configure both ends.
  • Leaving http_wait_end_of_query off when query results are produced only at the end. The socket can close while the client is still waiting.
  • Confusing http_connection_timeout (outbound, used by ClickHouse calling other servers) with the HTTP receive/send timeouts that apply to inbound traffic.

Frequently Asked Questions

Q: What is the difference between receive_timeout and keep_alive_timeout? A: receive_timeout applies during an active request when the server is waiting for the client to send more data. keep_alive_timeout applies between HTTP requests on a persistent connection. They cover different phases of the connection lifecycle.

Q: Should I just set every timeout to a huge value? A: No. Timeouts protect the server from leaked sockets and runaway sessions. Raise only the ones that actually fire for your workload. The defaults are reasonable for most cases.

Q: How do I pass these settings from a JDBC or HTTP client? A: Use the custom_settings query parameter or the HTTP header X-ClickHouse-Settings. Example: ?custom_settings=send_progress_in_http_headers=1,http_headers_progress_interval_ms=10000. Driver-specific properties also exist for connect, socket, and read timeouts on the client side; those need to be aligned with server values.

Q: Does max_execution_time cancel the query or just terminate the connection? A: It cancels the query. The server stops processing and returns an error to the client. The TCP connection itself is not torn down by max_execution_time.

Q: Why does my JDBC connection time out before my server-side receive_timeout? A: The JDBC driver has its own socket and read timeouts, often defaulted to 30 seconds. The driver enforces the lower of the two values. Configure socket_timeout (and similar) on the driver to match.

Subscribe to the Pulse Newsletter

Get early access to new Pulse features, insightful blogs & exclusive events , webinars, and workshops.

We use cookies to provide an optimized user experience and understand our traffic. To learn more, read our use of cookies; otherwise, please choose 'Accept Cookies' to continue using our website.