What is the Connection header?
The Connection header, defined in RFC 9110 Section 7.6.1, carries control options for the current connection only. Each option is a token, such as close, keep-alive or upgrade, and any option that matches a header name marks that header as hop-by-hop: meant for the immediate recipient, not for every hop on the chain. An intermediary MUST parse Connection before forwarding, remove every field it names, and then remove or replace Connection itself.
It is an HTTP/1.x mechanism. HTTP/2 and HTTP/3 carry connection metadata in their own framing; RFC 9113 Section 8.2.2 and RFC 9114 Section 4.2 forbid Connection and the fields it governs (Keep-Alive, Proxy-Connection, Transfer-Encoding and Upgrade), and any message containing them MUST be treated as malformed.
API Usage & Best Practices
- Strip hop-by-hop fields in any proxy you write: A gateway or reverse proxy that copies request headers to the upstream verbatim forwards fields that were never meant for it. Remove
Connection, every field it lists, and the known hop-by-hop fields (Keep-Alive,Proxy-Connection,TE,Transfer-Encoding,Upgrade) whether or not they are listed. Translating to HTTP/2 without doing this produces malformed messages that the next hop will reject. - Assume clients will abuse the list: A client controls
Connection, so it can name any header and have conforming proxies delete it in transit. RFC 9110 says a sender MUST NOT list a field intended for all recipients, such asCache-Control, but nothing stops an attacker doing so. Add the headers your edge injects for the back end (an authenticated-user header,X-Forwarded-For) after hop-by-hop stripping, never before, and have the back end treat their absence as a failure rather than as “no restriction”. - Use
closeto end the connection cleanly:Connection: closetells the peer the connection will not be reused after this response. Send it when draining a server for shutdown rather than resetting connections mid-request. - Do not set it by hand in HTTP/2 or HTTP/3 code: Frameworks that serve multiple protocols will drop or reject it. Persistence is the default in HTTP/1.1 anyway, so
Connection: keep-aliveis redundant there. - List the options that need it: A sender of
UpgradeorTEMUST also listupgradeorTEinConnection.
Examples
A WebSocket handshake marks Upgrade as hop-by-hop:
GET /v1/stream HTTP/1.1Host: api.example.comConnection: UpgradeUpgrade: websocketA server signaling that it will close the connection after this response:
HTTP/1.1 503 Service UnavailableConnection: closeRetry-After: 30Content-Type: application/problem+json