HTTP Connection Management

The TCP connection lifecycle, keep-alive/persistent connections, connection pooling, the HTTP/1.1 pipelining trap, the Connection header, timeouts, and when connections get reused.

To send one HTTP request, a TCP connection must be open underneath it. How you open, reuse, and close connections is largely invisible but decides latency and throughput. Opening a fresh connection per request is expensive, so modern HTTP has evolved to reuse connections as much as possible.

The TCP connection lifecycle

A TCP connection begins with a 3-way handshake (SYN → SYN-ACK → ACK), carries data, and closes with a 4-way teardown (FIN/ACK exchange). Over HTTPS, a TLS handshake stacks on top. So before the very first request even goes out, TCP round trips plus TLS round trips add up — for a distant server, hundreds of milliseconds can pass before any data arrives. Letting many requests share that fixed cost is the whole motivation for connection reuse.

Keep-alive and persistent connections

HTTP/1.0 closed the connection after one request by default. HTTP/1.1 flipped this, making persistent connections the default: one opened connection serves many requests back to back. You only send Connection: close when you explicitly want to close it. This pays the handshake cost once and lets later requests go out immediately over the reused connection.

GET /page1 HTTP/1.1
Host: example.com
Connection: keep-alive

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

Connection pooling

Browsers and HTTP client libraries keep open connections in a pool and reuse them for the next request to the same origin. In HTTP/1.1 a connection handles one request at a time, so for parallelism a client opens several (conventionally about six) connections per host. In HTTP/2 and HTTP/3, multiplexing lets a single connection carry many requests in parallel, so one connection per origin usually suffices.

The HTTP/1.1 pipelining trap

Pipelining is an HTTP/1.1 feature that sends multiple requests without waiting for each response. It seems like it should cut latency, but because the server must respond in the order requests arrived, a slow early request blocks fast later responses — head-of-line blocking. Worse, intermediary proxies implemented it inconsistently, so it broke in the wild. For these reasons browsers effectively disabled pipelining, and true parallelism was handed to HTTP/2 multiplexing instead.

When connections get reused, and timeouts

Connections aren't reused forever; several conditions must hold.

Ultimately, good connection management is about spreading the fixed handshake cost across as many requests as possible. HTTP/1.1 does it with keep-alive and multiple connections; HTTP/2 and HTTP/3 do it with a single multiplexed connection. If you build a client, explicitly configuring pool size, idle timeout, and retry policy is the key to both performance and reliability.