Back to HTTP Headers

Connection general both

Controls whether the TCP connection stays open after the current request — and lists hop-by-hop headers to strip before forwarding.

What it does

Connection has two purposes:

  1. Controls TCP connection persistence — tells the other party whether to keep the connection open (keep-alive) or close it (close) after this request/response.
  2. Lists hop-by-hop headers — any header names listed in Connection are hop-by-hop: they apply only to the current connection and must be stripped before forwarding.

Syntax

Connection: keep-alive
Connection: close
Connection: Upgrade
Connection: keep-alive, Upgrade

Values are comma-separated. Can be a directive (keep-alive, close) or the name of a hop-by-hop header to strip.

keep-alive vs close

Connection: keep-alive

Keep the TCP connection open after this request. The client can send another request on the same connection without the overhead of a new TCP handshake.

In HTTP/1.1, this is the default — connections are persistent unless explicitly closed. You rarely need to set it explicitly in modern setups.

Connection: close

Close the TCP connection after this response. The next request will require a new TCP (and TLS) handshake.

When to use it:

  • Server is about to shut down or restart
  • The response is the last in a long-lived streaming context
  • Signalling to a client or proxy that this connection is done

Hop-by-hop headers

Any header name listed in Connection is a hop-by-hop header — it's consumed by the next node in the chain (proxy, gateway) and must not be forwarded. This is how headers are scoped to a single connection rather than travelling end-to-end.

Example:

Connection: keep-alive, X-Custom-Proxy-Header

The proxy receiving this strips both Connection and X-Custom-Proxy-Header before forwarding. The origin server never sees them.

Built-in hop-by-hop headers (always treated as such regardless of Connection): Connection, Keep-Alive, Proxy-Authenticate, Proxy-Authorization, TE, Trailers, Transfer-Encoding, Upgrade.

WebSocket upgrade

Connection: Upgrade is part of the WebSocket handshake:

GET /ws HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

The Connection: Upgrade signals that the Upgrade header is hop-by-hop and that the client wants to switch protocols. The server responds with 101 Switching Protocols.

HTTP/2 and HTTP/3

Connection is forbidden in HTTP/2 and HTTP/3. HTTP/2 has its own connection management (multiplexing, flow control, stream priorities) that doesn't use Connection. An HTTP/2 server receiving a Connection header must treat it as a protocol error.

When a proxy receives an HTTP/1.1 request with Connection: keep-alive and forwards it over HTTP/2 to the origin, it strips the Connection header (and anything listed in it) before forwarding — this is the correct behaviour per spec.

Common mistakes and gotchas

Forwarding Connection headers through proxies. A naive proxy that forwards Connection: keep-alive to backends over HTTP/2 breaks the HTTP/2 protocol. Always strip Connection and the headers it lists before forwarding.

Using Connection for load balancer stickiness. Some developers try to use Connection: keep-alive to maintain affinity with a specific backend — but load balancers typically terminate TCP connections themselves and make independent connections to backends. Connection doesn't propagate past the load balancer.

Setting Connection: close on every response "to be safe." This kills connection reuse and dramatically increases latency and server load (every request = new TCP + TLS handshake). Only close when you have a reason.

Real-world examples

Default persistent connection (rarely needs to be explicit):

HTTP/1.1 200 OK
Connection: keep-alive
Content-Type: application/json
Content-Length: 142

Server closing connection after response:

HTTP/1.1 200 OK
Connection: close
Content-Type: text/html

WebSocket upgrade:

GET /chat HTTP/1.1
Host: ws.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Version: 13

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=

FAQ

Is keep-alive the default in HTTP/1.1?

Yes. HTTP/1.1 connections are persistent by default — you don't need to set Connection: keep-alive explicitly. It only becomes relevant when you want to signal close, or when you're a proxy that needs to manage connection lifetime explicitly.

What's the Keep-Alive header?

Keep-Alive is a separate header (not the Connection value) that provides parameters for persistent connections — timeout and max requests: Keep-Alive: timeout=5, max=1000. It's a hop-by-hop header and always listed in Connection: keep-alive, Keep-Alive when used. Largely irrelevant in HTTP/2+ and rarely needed in modern HTTP/1.1 setups.

Does Connection affect HTTP/1.0?

In HTTP/1.0, connections are closed after each request by default. Connection: keep-alive was used to opt in to persistent connections in HTTP/1.0, but support was inconsistent across implementations. HTTP/1.1 flipped the default, making close the opt-out rather than keep-alive the opt-in.

Fun fact

Before HTTP/1.1 persistent connections (1997), every single HTTP request required a separate TCP connection. Loading a webpage with 10 images meant 11 TCP handshakes (1 for HTML + 10 for images). On a high-latency connection, each handshake added 100–300ms. A typical page load could take several seconds just from connection overhead. Connection: keep-alive was one of the most impactful performance improvements in HTTP history — suddenly all those resources could reuse the same connection, cutting load times dramatically.

Related Headers