HTTP/1.1 vs HTTP/2 vs HTTP/3: A Story About Removing Different Kinds of Blocking
March 14, 2026
HTTP did not just get faster. Each version removed a specific kind of waiting that the previous one was stuck with.
HTTP/1.1 ties one request to one response on a connection. If response one is slow, response two waits behind it. That is application-layer head-of-line blocking. Pipelining was meant to fix this and never really worked in practice because of broken middleboxes. Browsers fell back to opening six or eight TCP connections per origin, which means six or eight handshakes, six or eight TLS sessions, six or eight competing congestion windows.
HTTP/2 collapsed that into one connection by introducing streams. Multiple requests and responses interleave as binary frames on a single TCP socket. Header compression via HPACK shaves bytes off every request. From the application layer, blocking is gone.
The catch is that HTTP/2 still runs on TCP, and TCP delivers bytes in order. If one packet on that socket is lost, the kernel will not hand any later bytes to the application until the missing one is retransmitted. Every stream stalls until the gap is filled. The blocking moved from layer seven to layer four, but it did not disappear.
HTTP/3 fixes that by abandoning TCP. QUIC runs over UDP, manages its own streams at the transport layer, and treats each stream as an independent reliable channel. A lost packet only stalls the stream it belongs to. The rest keep flowing. QUIC also bakes in TLS 1.3, so the handshake and the encryption setup happen together in fewer round trips, and a connection can migrate across network changes without redialing.
Here is the failure mode that makes this concrete. A gRPC service sits behind an AWS Network Load Balancer. The client holds one long-lived HTTP/2 connection through the NLB and multiplexes hundreds of streams over it. The path takes a brief blip, a single packet drops, and TCP stalls every stream on that socket at once. The client's health checks fire, the streams all error simultaneously, and the client opens fifty replacement connections in the same second. The NLB now has a thundering herd of handshakes and TLS negotiations to process. The downstream sees a synchronized retry storm.
On HTTP/3 the same blip costs you one stream. The other stream IDs keep delivering. There is no synchronized failure, so there is no synchronized retry.
The evolution is not about speed. It is about which streams can fail independently of which.
HTTP/2 fixed application-layer head-of-line blocking by multiplexing streams over one TCP connection. But it inherited TCP-level blocking. HTTP/3 over QUIC is what finally severs streams from each other on packet loss.
Originally posted on LinkedIn. View original.