Short answer
HTTP/2 solved application-level head-of-line blocking by multiplexing requests over one TCP connection, while HTTP/3 addressed the issue at the transport level by replacing TCP with QUIC over UDP.
Explanation
In HTTP/1.1, each request needs a separate connection or waits for the previous request to finish (Head-of-Line Blocking). HTTP/2 solved this by splitting data into binary frames and transmitting concurrent streams over the same TCP connection, with header compression (HPACK). But if a single TCP packet is lost due to network interference, TCP stops passing all other streams until it is retransmitted. HTTP/3 over QUIC addresses this: each data stream is independent, packet loss in one stream does not affect others, and the TLS 1.3 handshake can be combined into one step (0-RTT).
Code example
import httpx
# pip install "httpx[http2]" — many requests are multiplexed over ONE TCP connection
with httpx.Client(http2=True) as client:
response = client.get("https://www.google.com")
print(response.http_version) # "HTTP/2"
# HTTP/3 (QUIC over UDP) is advertised by the server in the Alt-Svc response header
print(response.headers.get("alt-svc")) # e.g. h3=":443"; ma=2592000
# Try it from the command line: curl --http3 -I https://cloudflare-quic.comCommon mistakes
- Believing that HTTP/3 is insecure because it uses UDP; QUIC includes mandatory TLS 1.3 encryption in every connection and cannot run as unencrypted plaintext.