Server

HTTP/1.1 vs HTTP/2 vs HTTP/3, in Practice

By Prabath Thalangama· October 24, 2026· 3 min read
#http#networking#performance

Introduction

Three major HTTP versions are in active use. They speak the same semantics (methods, status codes, headers) but move bytes very differently, and the differences show up as real performance characteristics. Here's what changed and what it means for a server operator.

HTTP/1.1

  • One request at a time per connection. A response must finish before the next request on that connection can start (head-of-line blocking).
  • Browsers work around this by opening 6 parallel connections per host — hence "domain sharding" tricks in the 2010s.
  • Headers are plaintext and repeated in full on every request (cookies, user-agent — often more bytes than the request line).
  • Keep-alive reuses a connection for sequential requests; pipelining (sending the next request before the response) was specified but never worked reliably and is effectively dead.

HTTP/2

  • Multiplexing: many concurrent request/response streams over a single TCP connection, interleaved as frames. No more 6-connection limit.
  • HPACK header compression: a shared dynamic table means repeated headers cost a few bytes.
  • Server push (deprecated in practice — browsers removed support; use 103 Early Hints instead).
  • Still TCP. If one packet is lost, TCP holds back every stream until it's retransmitted — transport-level head-of-line blocking. HTTP/2 solved the application-level version but not this.
  • Requires TLS in every browser implementation (ALPN negotiates h2).

HTTP/3

  • Runs over QUIC, which is over UDP.
  • QUIC has independent streams at the transport layer, so a lost packet only stalls the stream it belonged to — the others keep flowing.
  • Connection setup and TLS 1.3 are combined: 1-RTT to first byte, 0-RTT on resumption.
  • Connection migration: a connection is identified by a connection ID, not the 4-tuple, so switching from Wi-Fi to cellular doesn't drop it.
  • Encryption is mandatory and covers almost the whole packet, including most of the transport header.
  • Downsides: UDP is sometimes rate-limited or blocked on corporate/older networks (browsers fall back to HTTP/2), and it's more CPU-intensive per byte.

When each still matters

Situation Effect
Many small assets, one host HTTP/2 is a big win over 1.1
Lossy / high-latency link (mobile, satellite) HTTP/3 clearly beats HTTP/2
Large single download All three are similar
Client behind a UDP-blocking firewall Falls back to HTTP/2; no harm
A CDN in front You likely already get h2/h3 to the client regardless of your origin

Hands-on

# What did this request negotiate?
curl -sI --http2 https://example.com | head -1
curl -sI --http3 https://example.com | head -1      # curl 7.66+ with HTTP/3 support

# ALPN protocols the server offers
openssl s_client -connect example.com:443 -alpn h2,http/1.1 </dev/null 2>/dev/null | grep ALPN

# Nginx: enable both
#   listen 443 ssl;
#   http2 on;
#   http3 on;              # Nginx 1.25+ with the QUIC module
#   add_header Alt-Svc 'h3=":443"; ma=86400';

The Alt-Svc header is how a server advertises HTTP/3 — the browser connects over h2 first, sees the header, and upgrades subsequent connections.

Verification and troubleshooting

  • Browser shows HTTP/1.1 despite http2 on — HTTP/2 needs TLS and ALPN. A plain http:// connection, or a proxy in front doing HTTP/1.1 to your origin.
  • HTTP/3 never used — no Alt-Svc header, UDP/443 blocked between client and server, or the client doesn't support it. Not a problem, just no upside.
  • HTTP/2 slower than expected on a lossy link — TCP head-of-line blocking. This is the exact case HTTP/3 fixes.
  • Server push does nothing — it's been removed from browsers. Switch to Link: </style.css>; rel=preload and 103 Early Hints.
  • Too many streams / RST_STREAM floods — HTTP/2 rapid-reset attacks (CVE-2023-44487). Keep your server patched and cap concurrent streams.
PrabathStuck on something this site can't fix?Reach out to Prabath directly on LinkedIn.