Back to HTTP Headers

Keep-Alive general both

Provides parameters (timeout and max requests) for a persistent connection — always paired with Connection: keep-alive.

What it does

Keep-Alive provides tuning parameters for a persistent HTTP/1.1 connection — specifically, how long the connection should stay idle before being closed, and how many more requests it will accept before closing. It's not what actually enables persistent connections (Connection: keep-alive does that, and is HTTP/1.1's default behavior regardless) — Keep-Alive just fine-tunes the lifetime of a connection that's already persistent.

It's a hop-by-hop header, meaning it only applies to the current connection and must be stripped by any intermediary (proxy, gateway) before forwarding — and per spec, it's only meaningful when explicitly listed in Connection.

Syntax

Keep-Alive: timeout=5, max=1000
Keep-Alive: timeout=5

Two optional parameters, comma-separated:

  • timeout — seconds the server will keep an idle connection open before closing it
  • max — maximum number of requests the server will serve on this connection before closing it (largely a legacy parameter on modern servers — see gotchas below)

How it relates to Connection

Keep-Alive only has meaning alongside Connection: keep-alive, and per RFC 9112, it should be explicitly listed as hop-by-hop:

Connection: keep-alive, Keep-Alive
Keep-Alive: timeout=5, max=1000

Sending Keep-Alive without Connection: keep-alive (or without listing it in Connection) has no defined effect — it's the Connection header that actually establishes persistence; Keep-Alive just tunes it.

Common mistakes and gotchas

Assuming Keep-Alive enables persistent connections. It doesn't — HTTP/1.1 connections are persistent by default. Keep-Alive only adjusts timeout/max parameters for a connection that's already going to stay open regardless of whether this header is present.

Relying on max for connection pooling logic. Some older documentation treats max as meaningful for controlling exactly how many requests a connection handles — in practice, most modern server software (Nginx, for example) doesn't strictly enforce this the way older Apache configurations once did, so behavior varies by server rather than being a hard guarantee clients can depend on.

Setting an aggressively short timeout. A very low timeout value causes connections to close (and require a fresh TCP+TLS handshake) between closely-spaced requests, undermining the entire performance benefit persistent connections are meant to provide.

Expecting this header to matter in HTTP/2 or HTTP/3. Like Connection, Keep-Alive is meaningless in HTTP/2+ — those protocols have their own connection and stream management (multiplexing over a single connection) that doesn't use either header.

Real-world examples

Typical Nginx-style response:

HTTP/1.1 200 OK
Connection: keep-alive
Keep-Alive: timeout=65
Content-Type: text/html

Explicit hop-by-hop declaration:

HTTP/1.1 200 OK
Connection: keep-alive, Keep-Alive
Keep-Alive: timeout=5, max=100
Content-Type: application/json

FAQ

Do I need to set Keep-Alive manually?

Almost never — most web servers and reverse proxies (Nginx, Apache) set sensible defaults automatically. You'd only tune it explicitly if you have a specific reason to adjust idle connection lifetime, like reducing server-side connection pressure under heavy load.

What happens if Keep-Alive is missing but Connection: keep-alive is present?

The connection still stays persistent — Connection: keep-alive alone is sufficient for that. The client and server just fall back to their own default idle timeout behavior rather than following an explicit value.

Is Keep-Alive the same thing as TCP keep-alive?

No — this is a common point of confusion. HTTP's Keep-Alive header governs application-layer persistent-connection behavior. TCP keep-alive is a completely separate, lower-level mechanism (OS socket option) for detecting whether an idle TCP connection's peer is still reachable. They share a name but operate at different layers.

Does Keep-Alive matter for HTTP/2?

No — Connection and Keep-Alive are both meaningless in HTTP/2 and HTTP/3, which handle connection persistence and multiplexing through their own binary framing protocol rather than these HTTP/1.1-era headers.

Fun fact

The max parameter dates back to an era when servers were far more conservative about resource usage — Apache's classic prefork model, for instance, historically defaulted to capping keep-alive connections at 100 requests specifically to prevent a single client from monopolizing a worker process indefinitely. Modern event-driven servers (Nginx, and Apache's own newer MPMs) handle concurrent connections so differently that this kind of hard request-count cap is far less necessary — a good example of an HTTP header parameter whose original motivation has faded even though the header itself is still technically in use.