skip to content

In a Tomcat server.xml <Connector>, what does the connectionTimeout attribute actually time out, and how does keepAliveTimeout differ from it?

level: juniorimportance: should knowfreq 45%

answer

  1. waiting for the request line
  2. idle gap between requests
  3. one inherits the other's value
  4. says nothing about servlet runtime
  5. the proxy pool race after quiet periods

basics

~20 s

connectionTimeout is how long Tomcat waits, after accepting a connection, for the request line to arrive. keepAliveTimeout is how long it waits for the next request on an already-used connection, and defaults to the connectionTimeout value.

solid answer

~40 s

`connectionTimeout` is a *read-the-request* timeout: once the socket is accepted, Tomcat waits that many milliseconds for the client to present the request URI line, and closes the connection if it does not. Tomcat's documented default is 60000 ms, though the shipped `server.xml` sets `connectionTimeout="20000"`. `keepAliveTimeout` covers the idle gap *between* requests on a persistent connection — how long an already-used connection is held open waiting for the next request — and if you do not set it, it inherits the `connectionTimeout` value. Neither one limits how long your servlet may take: a request that has been fully read can run for minutes without either timer firing. Bounding slow application work is the job of your own downstream client timeouts, and for asynchronous requests the connector's `asyncTimeout` (default 30000 ms).

go deeper

for a junior

Be able to say plainly that connectionTimeout waits for the request to arrive and keepAliveTimeout waits for the next request on the same connection, and that the second defaults to the first.

for a middle

Explain the defaults, the inheritance, and above all what these timers do not cover — servlet execution time — plus where asyncTimeout fits for asynchronous requests.

for a senior

Show you can read a stalled connection: which timer fired, whether an access-log entry exists, and why a keep-alive window shorter than the fronting proxy's pool produces intermittent resets after idle periods.

for a principal

Own the idle-timeout ordering across the whole path so each hop's window is longer than the client pool in front of it, and decide when maxKeepAliveRequests should force rebalancing across instances.

## Two different silences Both attributes answer the same shape of question — *how long will Tomcat tolerate a connection on which nothing is happening?* — but they cover different moments in the connection's life, and confusing them is the reason people are surprised that a "20 second timeout" did not stop a 90-second request. **connectionTimeout** applies immediately after the socket is accepted. Tomcat is waiting for the client to say what it wants — the request line, for example `GET /orders HTTP/1.1`. If the client connects and then says nothing, this timer closes the connection. The documented default is 60000 milliseconds; the `server.xml` that ships with Tomcat overrides it to `20000`. **keepAliveTimeout** applies after a response has been written on a persistent connection. The exchange is over, the socket stays open, and Tomcat waits for the client to send another request on it. If nothing arrives within this window, Tomcat closes the connection to reclaim the resource. When the attribute is absent, its value is the connector's `connectionTimeout`. ```xml <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" keepAliveTimeout="20000" maxKeepAliveRequests="100" redirectPort="8443"/> ``` ## What neither of them does Neither attribute limits **request processing time**. Once the request has been read and handed to a servlet, no connector timer is counting: a servlet blocked for two minutes on a database call keeps its request thread for two minutes. That is exactly the gap that lets a slow dependency exhaust the thread pool while every connector timeout looks correctly configured. Bounding that work is the application's job — connect and read timeouts on the HTTP or JDBC clients your code calls — not the connector's. The one connector-level exception is `asyncTimeout` (default 30000 ms), which applies to requests that have entered asynchronous mode via `AsyncContext`; there is no container thread parked on those, so the container itself has to decide when to give up. ## Why the keep-alive window is a capacity decision A long `keepAliveTimeout` means idle connections linger. On the NIO connector that is comparatively cheap — an idle connection is polled, not owned by a thread — but it still consumes a socket and counts against `maxConnections`. A short one closes connections that a client was about to reuse, forcing a new TCP (and for HTTPS, a new TLS) setup on the next request. The answer depends heavily on **who the client is**. Behind a reverse proxy, the connections are a small, fixed set from a pool that will reuse them constantly, so a generous keep-alive window is nearly free and avoids repeated handshakes. Facing the public internet directly, the connection population is huge and mostly abandoned, and a short window protects `maxConnections`. `maxKeepAliveRequests` (default 100) is the companion knob: it caps how many requests one connection may serve before Tomcat closes it, which is how a server periodically forces clients to rebalance across instances. ## The classic mismatch with the proxy in front There is a well-known race whenever a pooled client sits in front of a keep-alive server. If Tomcat's `keepAliveTimeout` is *shorter* than the idle timeout of the proxy's upstream connection pool, the proxy will occasionally pick a connection that Tomcat has already decided to close, write a request onto it, and get a reset. The symptom is a small, maddening rate of failed requests concentrated just after quiet periods. The rule of thumb on the Tomcat side is that the server's idle window should be at least as long as the client pool's, so the *client* is the party that retires idle connections rather than discovering closed ones. If you cannot control both ends, the alternative is a client that retries an idempotent request when the failure occurs before any response byte was read. ## Reading a stalled connection When you are told "requests hang", the timeout attributes tell you which stage to look at. A connection that is accepted and then closed after exactly `connectionTimeout` milliseconds with no access-log entry means the client never sent a complete request line — a health checker that opens a socket and closes it, a TLS client talking to a plaintext connector, or a port scanner. A connection that dies after `keepAliveTimeout` with the log showing a successful response earlier is normal housekeeping, not an error, and should not be alerted on.

  • A servlet blocks for 90 seconds on a database call while connectionTimeout is 20000. Why does Tomcat not abort it?
    Because `connectionTimeout` stops counting once the request has been read. Nothing in the connector supervises servlet execution on a synchronous request, so the exec thread stays occupied for the full 90 seconds. The bound has to come from the JDBC or HTTP client the code calls, not from the connector.
  • Should Tomcat's keepAliveTimeout be shorter or longer than the idle timeout of the proxy pooling connections to it?
    Longer. If Tomcat closes idle connections first, the proxy will occasionally write a request onto a connection Tomcat has already closed and see a reset — a low-rate failure that clusters just after idle periods. Letting the client retire connections first makes the close deterministic instead of racy.

saying these in an interview costs you the question

  • Thinks connectionTimeout limits how long a request may run
  • Assumes keepAliveTimeout must be configured explicitly to exist
  • Confuses it with the timeout of the downstream call the servlet makes
  • Believes a long keep-alive window costs one thread per connection
  • Sets keep-alive shorter than the proxy pool and calls the resets a network fault

context