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:
- Controls TCP connection persistence — tells the other party whether to keep the connection open (
keep-alive) or close it (close) after this request/response. - Lists hop-by-hop headers — any header names listed in
Connectionare 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.