Skip to main content

HTTP/2 vs HTTP/3

HTTP/2 and HTTP/3 solve the same problem – multiplexing many requests efficiently over one connection – but at different layers of the stack. HTTP/2 runs over TCP. TCP guarantees reliable, ordered delivery at the transport layer. If a single TCP packet is lost, all streams on that connection pause until the packet is retransmitted, even streams that have nothing to do with the lost packet. This is TCP head-of-line blocking. HTTP/2's application-layer multiplexing cannot escape the TCP constraint it runs on. HTTP/3 runs over QUIC, which uses UDP as its transport. QUIC implements reliable delivery per stream rather than per connection. A lost UDP packet only blocks the stream it belongs to – other streams continue unaffected. This is the fundamental architectural difference. QUIC loss recovery mechanism: Each QUIC packet has a unique packet number (monotonically increasing, never reused). The receiver sends ACK frames acknowledging received packet numbers. QUIC detects loss via: (1) three ack-eliciting packets sent after the lost packet without it being acknowledged (rack-based detection), or (2) a probe timeout (PTO). On detection, QUIC retransmits the stream data (not the original packet – new packet numbers always). This per-stream retransmission means stream 5's lost packet does not hold up stream 3's data. 0-RTT connection resumption – replay risk: QUIC 0-RTT allows a client to send data in the first packet using a pre-shared key from a previous connection (PSK). This eliminates the connection establishment RTT for repeat visits. Critical caveat: 0-RTT data can be replayed by a network attacker. An attacker can capture a 0-RTT packet and retransmit it to the server – the server sees it as a new request. RFC 9001 §8.1 requires that servers only process 0-RTT for idempotent operations (GET, HEAD) and that applications take care not to process non-idempotent 0-RTT requests without replay protection (e.g., session tickets with replay tracking). QPACK vs HPACK – why they differ: HPACK (HTTP/2) uses a single shared dynamic table across all streams on a connection. Entries are added and referenced in order. This requires perfectly ordered delivery – a dynamic table entry added on stream 1 must be visible to stream 3. This works in TCP because TCP guarantees order. QPACK (HTTP/3, RFC 9204) separates the encoder and decoder streams from request/response streams. The encoder sends table updates on a dedicated unidirectional QPACK encoder stream. The decoder acknowledges them on a QPACK decoder stream. Request streams reference table entries only after the decoder confirms they're available. This allows QPACK to avoid head-of-line blocking that HPACK would cause on QUIC's out-of-order streams. In practice the difference matters most on lossy networks (mobile, high-latency links). On a typical low-loss wired connection, HTTP/2 and HTTP/3 perform similarly. On mobile networks where 1–2% packet loss is common, HTTP/3's elimination of TCP head-of-line blocking produces measurable latency improvements. Connection migration: TCP connections are identified by the 4-tuple (src IP, src port, dst IP, dst port). When a mobile device switches from Wi-Fi to cellular, all four values change – every TCP connection breaks. QUIC connections are identified by a Connection ID (an opaque byte sequence in every QUIC packet). When the IP changes, the client sends a PATH_CHALLENGE on the new path, the server responds with PATH_RESPONSE, and the connection migrates without interruption. Active HTTP/3 streams survive a network change. Migration path: HTTP/3 is negotiated via Alt-Svc header or HTTPS DNS record. Clients fall back to HTTP/2 automatically when QUIC is blocked. There are no API-level changes between HTTP/2 and HTTP/3 – the same request/response semantics apply.

HTTP/2 (RFC 9113) multiplexes requests over a single TLS-encrypted TCP connection, eliminating HTTP/1.1 head-of-line blocking at the HTTP layer. HTTP/3 (RFC 9114) goes further by replacing TCP with QUIC (UDP-based), eliminating TCP-level head-of-line blocking entirely and adding 0-RTT connection resumption. HTTP/3 is now the default on most CDNs. For most deployments behind a proxy or CDN, enabling HTTP/3 is a configuration change that improves performance with zero application changes.

FeatureHTTP/2HTTP/3
TransportTCP + TLS 1.2/1.3QUIC (UDP) with built-in TLS 1.3
RFCRFC 9113 (2022)RFC 9114 (2022)
Head-of-line blockingEliminated at HTTP layer; still exists at TCP layerEliminated at both HTTP and transport layer
Connection setupTCP 3-way handshake + TLS 1-RTT = 2 RTTsQUIC 1-RTT new, 0-RTT resumption
Header compressionHPACK (RFC 7541) – shared dynamic table requires ordered delivery; vulnerable to TCP HOL blockingQPACK (RFC 9204) – separate encoder/decoder control streams; dynamic table updates acknowledged before use; no HOL blocking
MultiplexingMultiple HTTP streams over one TCP connectionIndependent QUIC streams – no cross-stream blocking
Connection migrationNot supported – 4-tuple (src IP, src port, dst IP, dst port) change breaks connectionQUIC Connection IDs in every packet – client sends PATH_CHALLENGE on new path, server responds, connection migrates without interruption
0-RTT resumptionTLS 1.3 session resumption (0-RTT possible but separate from HTTP/2)QUIC 0-RTT: client sends data in first packet using pre-shared key. Eliminates connection RTT for repeat visitors. Replay risk: only safe for idempotent (GET/HEAD) requests (RFC 9001 §8.1).
Server pushSupported (rarely used, deprecated in practice)Removed from HTTP/3 spec
Firewall compatibilityUniversal – TCP 443 passes all firewallsUDP 443 may be blocked by enterprise firewalls; falls back to HTTP/2
Deployment statusDefault on all modern web serversDefault on Cloudflare, Fastly, Google, Meta. ~33% of web traffic (2026)
Application changesNone from HTTP/1.1None from HTTP/2 – same request/response API

When to use HTTP/2

HTTP/2 is the safe choice when: you need maximum firewall compatibility (enterprise environments that block UDP), your server infrastructure does not yet support QUIC, or you are behind a reverse proxy that handles TLS termination without QUIC support. HTTP/2 is still a significant improvement over HTTP/1.1 and is universally supported.

When to use HTTP/3

HTTP/3 is the right choice for: public-facing APIs and websites served via CDN (Cloudflare, Fastly, AWS CloudFront all support it), mobile-first applications where lossy networks are common, applications requiring low latency on reconnection (0-RTT), and any scenario where clients frequently change networks (Wi-Fi to cellular). Enable it alongside HTTP/2 fallback – no client-side changes required.

Common Mistakes

  • Assuming HTTP/3 requires API or application code changes – it does not. HTTP/3 is a transport upgrade. The same HTTP methods, headers, and status codes apply.
  • Not enabling HTTP/2 fallback when deploying HTTP/3 – always configure both. QUIC is blocked on many enterprise networks. Nginx: listen 443 quic; listen 443 ssl; both.
  • Treating the absence of HTTP/3 as a bug – many corporate proxies and VPNs block UDP on port 443. The fallback to HTTP/2 is designed and expected behavior.
  • Confusing QUIC with HTTP/3 – QUIC (RFC 9000) is the transport protocol. HTTP/3 (RFC 9114) is the application protocol that runs on QUIC. WebTransport also runs on QUIC but is a different application protocol.

FAQ

Does HTTP/3 require HTTPS?

Yes. QUIC integrates TLS 1.3 natively and there is no way to use HTTP/3 without encryption. HTTP/3 is inherently HTTPS. Attempting to use HTTP/3 over plaintext is not possible.

How do I check if a site uses HTTP/3?

In Chrome DevTools: Network tab, Protocol column shows h3 for HTTP/3, h2 for HTTP/2. Via curl: curl --http3 -I https://example.com. Via dig: check for HTTPS DNS record with alpn=h3.

Is HTTP/3 faster than HTTP/2 on a fast wired connection?

Marginally or imperceptibly on low-loss wired connections. The advantage is most pronounced on mobile networks with packet loss (1–2% loss), where HTTP/3 can reduce page load times by 10–20% due to eliminating TCP head-of-line blocking.