HTTP/3 and QUIC: UDP, Zero Round Trips, and the End of Head-of-Line Blocking
How Google's experimental protocol became the standard that moved HTTP off TCP after 30 years, and why your next connection might complete before the handshake.
- DATE:
- APR.28.2026
- READ:
- 18 MIN
From gQUIC to IETF QUIC
HTTP ran on TCP for its entire existence. HTTP/1.0 in 1996, HTTP/1.1 in 1997, HTTP/2 in 2015 — every version assumed a reliable, ordered byte stream underneath. Then Google broke the assumption.
The timeline:
2012 — Engineers at Google designed QUIC internally (Quick UDP Internet Connections). The goal was to eliminate the multi-round-trip cost of TCP + TLS connection setup, which dominated latency on mobile networks.
2013 — Google publicly announced QUIC and began experimenting in Chrome. All traffic to Google services could negotiate QUIC via the Alt-Svc header. By late 2013, roughly 50% of Chrome-to-Google traffic used gQUIC.
2016 — The IETF established the QUIC Working Group. Google submitted gQUIC as the starting point, but the working group made clear from the start that the IETF version would be a new protocol, not a rubber stamp.
2017 — IETF QUIC diverged significantly from gQUIC. The IETF version replaced Google’s custom crypto with TLS 1.3, changed the wire format, redesigned the header structure, and introduced a new header compression scheme. The two protocols are not interoperable.
October 2018 — Mark Nottingham proposed renaming the protocol from “HTTP over QUIC” to “HTTP/3.” The name stuck. This was the moment it became clear that QUIC was not a transport curiosity but the foundation of the next major HTTP version.
May 2021 — Three foundational RFCs published as Proposed Standards: RFC 9000 (QUIC Transport Protocol), RFC 9001 (Using TLS to Secure QUIC), and RFC 9002 (QUIC Loss Detection and Congestion Control).
June 2022 — RFC 9114 (HTTP/3) and RFC 9204 (QPACK: Field Compression for HTTP/3) published. HTTP/3 was officially standardized, five years after the IETF working group began.
Why UDP instead of TCP
The question everyone asks first: why would you build a reliable transport protocol on top of an unreliable one?
The answer is ossification. TCP is baked into everything — kernel stacks, middleboxes, firewalls, NATs, load balancers, hardware offload engines. Deploying a change to TCP’s wire format requires updating every device in the path. In practice, this means TCP changes take years to propagate, if they propagate at all. TCP extensions like Fast Open (RFC 7413, 2014) still see limited deployment a decade later because middleboxes strip the options they don’t recognize.
UDP passes through existing infrastructure unmodified. It has no state, no options, no extensions for middleboxes to interfere with. By building QUIC on top of UDP, the IETF gained the ability to iterate on the transport protocol without waiting for the entire internet to upgrade.
There is a deeper reason too. TCP’s head-of-line blocking problem is unfixable within TCP itself. When HTTP/2 multiplexes multiple streams over a single TCP connection and one packet is lost, TCP stalls the entire connection until that packet is retransmitted and received. Every stream blocks, even the ones whose data arrived successfully. This is the problem HTTP/2 was supposed to solve, and it couldn’t, because TCP treats the byte stream as one ordered sequence.
QUIC moves the transport logic to user space. The kernel sees UDP datagrams. QUIC handles reliability, ordering, congestion control, and encryption itself. This means protocol updates ship as library updates, not kernel patches.
Connection establishment
Connection setup latency is where QUIC’s design pays off most visibly.
TCP + TLS 1.3 (HTTP/2): 2 RTT
A fresh HTTP/2 connection requires two sequential round trips before application data can flow:
Client Server
| |
|--- SYN --------------------------->|
|<-- SYN-ACK ------------------------| 1 RTT (TCP handshake)
|--- ACK --------------------------->|
| |
|--- ClientHello ------------------->|
|<-- ServerHello, Finished ----------| 2 RTT (TLS 1.3)
|--- Finished, HTTP request -------->|
|<-- HTTP response ------------------|With TLS 1.2, the TLS handshake takes two round trips instead of one, for a total of three RTT. TLS 1.3 reduced this to one RTT, but you still pay for the TCP handshake underneath.
QUIC 1-RTT
QUIC combines the transport handshake and the TLS 1.3 handshake into a single flight:
Client Server
| |
|--- Initial (ClientHello) --------->|
|<-- Initial (ServerHello) + HS -----| 1 RTT
|--- HS Finished, HTTP request ----->|
|<-- HTTP response ------------------|The QUIC Initial packet carries the TLS ClientHello. The server responds with its ServerHello and handshake messages in the same flight. After one round trip, the handshake is complete and the client can send application data. One RTT saved on every new connection.
QUIC 0-RTT
If the client has connected to this server before and cached a session ticket (via TLS’s NewSessionTicket mechanism), it can send application data alongside the very first packet:
Client Server
| |
|--- Initial + 0-RTT data --------->| 0 RTT
|<-- Initial + HS + response -------|Zero round trips. The client sends its request before the handshake completes. The server can respond immediately.
+---------------+-----------------+--------------------+ | Mode | RTT before data | Requirement | +---------------+-----------------+--------------------+ | TCP + TLS 1.2 | 3 RTT | None | +---------------+-----------------+--------------------+ | TCP + TLS 1.3 | 2 RTT | None | +---------------+-----------------+--------------------+ | QUIC 1-RTT | 1 RTT | None | +---------------+-----------------+--------------------+ | QUIC 0-RTT | 0 RTT | Cached session | | | | ticket | +---------------+-----------------+--------------------+
Stream multiplexing without head-of-line blocking
This is the core architectural win of HTTP/3 over HTTP/2.
In HTTP/2, all streams share a single TCP connection. TCP delivers bytes in order. If packet 5 is lost, TCP holds packets 6, 7, and 8 in its receive buffer until packet 5 is retransmitted and arrives, even if those later packets belong to completely different HTTP streams. Every stream blocks on every lost packet.
In HTTP/3, each QUIC stream is independent at the transport layer. A lost packet on stream A causes only stream A to pause. Streams B, C, and D continue receiving data without interruption. The transport protocol knows about stream boundaries and enforces ordering only within a single stream.
HTTP/2 over TCP (packet 3 lost):
Stream A: [1] [2] [_] ← blocked
Stream B: [4] [5] [6] ← also blocked (same TCP connection)
Stream C: [7] [8] [9] ← also blocked
HTTP/3 over QUIC (stream A packet lost):
Stream A: [1] [2] [_] ← blocked
Stream B: [4] [5] [6] ← delivered
Stream C: [7] [8] [9] ← deliveredOn clean networks with no packet loss, this distinction doesn’t matter. On lossy networks — mobile, congested WiFi, intercontinental links — it is the difference between a page that loads and a page that hangs.
QPACK header compression (RFC 9204)
HTTP/2 used HPACK (RFC 7541) for header compression. HPACK maintains a dynamic table of previously seen header fields and uses index references to compress repeated headers. It works well, but it has a dependency: the encoder and decoder must process headers in the same order. The dynamic table state must stay synchronized.
This is a problem for QUIC. QUIC does not guarantee that streams are delivered in order. If request 1 adds a header to the dynamic table and request 2 references that entry, but request 2 arrives before request 1, the decoder can’t resolve the reference.
QPACK solves this with two dedicated unidirectional streams:
- Encoder stream — the encoder sends dynamic table updates on this stream. Because it’s a single stream, updates are ordered.
- Decoder stream — the decoder sends acknowledgements back, telling the encoder which updates have been processed.
The encoder can choose: reference the dynamic table (better compression, but the decoder might have to wait for the update) or use a literal encoding (larger, but no blocking). This is an explicit tradeoff between compression ratio and head-of-line blocking risk. QPACK gives both the encoder and the decoder the information they need to make this tradeoff at runtime.
Connection migration
TCP connections are identified by a four-tuple: source IP, source port, destination IP, destination port. Change any one of these and the connection breaks. When your phone switches from WiFi to cellular, every TCP connection dies and must be re-established.
QUIC connections are identified by Connection IDs — opaque byte sequences chosen by each endpoint. The Connection ID is carried in the QUIC packet header, not derived from the IP/port tuple. When the underlying network path changes, the Connection ID stays the same and the QUIC connection survives.
The migration process:
- The client detects a network change (new local IP address).
- The client sends a PATH_CHALLENGE frame on the new path, containing a random 8-byte payload.
- The server responds with a PATH_RESPONSE frame echoing the same payload.
- Once path validation succeeds, both endpoints switch to the new path.
NAT rebinding — where a NAT device silently assigns a new port mapping — is handled transparently. The server sees a packet from a new source address but with a valid Connection ID, validates the path, and continues.
Loss recovery improvements (RFC 9002)
QUIC’s loss recovery is a clean-sheet redesign that fixes several long-standing TCP problems.
Many ACK ranges. TCP’s Selective Acknowledgement (SACK) option supports at most three ranges. QUIC ACK frames can report an arbitrary number of ranges, giving the sender a much more accurate picture of which packets arrived.
No reneging. In TCP, a receiver is technically allowed to discard data it previously SACKed (reneging). This forces the sender to treat SACKs as advisory. In QUIC, once a packet is acknowledged, it stays acknowledged. The sender can trust its loss detection state.
Monotonically increasing packet numbers. TCP uses sequence numbers that wrap and reuses them on retransmission, creating the retransmission ambiguity problem: did the ACK acknowledge the original or the retransmit? QUIC packet numbers always increase. Retransmitted data gets a new, higher packet number. RTT measurements are unambiguous.
Pluggable congestion control. QUIC separates loss detection from congestion control. RFC 9002 specifies NewReno as the default, but the interface is designed for pluggability. Implementations support BBR (v1 and v2), CUBIC, and experimental algorithms. Since QUIC runs in user space, switching congestion control algorithms doesn’t require a kernel update.
Performance benchmarks
The numbers vary by implementation, network conditions, and workload. Here are results from published studies and production deployments.
+--------------------+----------+----------------+------------------+ | Condition | HTTP/2 | HTTP/3 | Difference | +--------------------+----------+----------------+------------------+ | Clean network, low | Baseline | +5-15% CPU | QUIC slower | | latency | | | | +--------------------+----------+----------------+------------------+ | 2% packet loss | Baseline | -30% latency | QUIC faster | +--------------------+----------+----------------+------------------+ | 5% packet loss | Baseline | -55% latency | QUIC much faster | +--------------------+----------+----------------+------------------+ | High loss (mobile) | Baseline | -88% latency | QUIC dominant | +--------------------+----------+----------------+------------------+ | Mobile page loads | Baseline | -30% latency | QUIC faster | | (Akamai) | | | | +--------------------+----------+----------------+------------------+ | File downloads | Baseline | -52% time | QUIC faster | | (Akamai) | | | | +--------------------+----------+----------------+------------------+ | TTFB (AWS | Baseline | -10% | QUIC faster | | CloudFront) | | | | +--------------------+----------+----------------+------------------+ | Page load (AWS | Baseline | -15% | QUIC faster | | CloudFront) | | | | +--------------------+----------+----------------+------------------+ | Throughput, fast | Baseline | -45% data rate | QUIC slower | | network | | | | +--------------------+----------+----------------+------------------+
The pattern is consistent: HTTP/3 wins on bad networks and loses on good ones.
On clean, low-latency networks, QUIC’s user-space processing costs roughly 2x the CPU of kernel TCP. The encryption overhead (QUIC encrypts nearly every packet, including headers) and the per-packet processing in user space add up. For bulk transfers on fast links, TCP with hardware offload still wins on raw throughput.
On lossy, high-latency, or mobile networks — which describes the majority of real-world web traffic — QUIC’s elimination of head-of-line blocking and reduced connection setup time dominate. The worse the network, the bigger QUIC’s advantage.
Adoption
As of April 2026, HTTP/3 is no longer optional infrastructure. It is the default for the majority of web traffic.
Usage by websites: W3Techs reports approximately 35.9% of websites serve HTTP/3 as of April 2026. Meta routes roughly 75% of its traffic over QUIC. By volume, over 40% of global web traffic uses HTTP/3.
Browser support
+---------+---------+------+--------------------+ | Browser | Version | Year | Notes | +---------+---------+------+--------------------+ | Chrome | 87+ | 2020 | Enabled by default | +---------+---------+------+--------------------+ | Firefox | 88+ | 2021 | Enabled by default | +---------+---------+------+--------------------+ | Safari | 14+ | 2020 | macOS Big Sur, iOS | | | | | 14 | +---------+---------+------+--------------------+ | Edge | 87+ | 2020 | Chromium-based | +---------+---------+------+--------------------+
Every major browser has supported HTTP/3 by default since 2021. There is no browser support gap to worry about.
CDN and cloud support
+------------------+----------------+--------------------+ | Provider | HTTP/3 Support | Notes | +------------------+----------------+--------------------+ | Cloudflare | Yes | Enabled by default | | | | on all plans | +------------------+----------------+--------------------+ | AWS CloudFront | Yes | Enabled 2022, all | | | | distributions | +------------------+----------------+--------------------+ | Akamai | Yes | Production since | | | | 2023 | +------------------+----------------+--------------------+ | Fastly | Yes | Built on | | | | H2O/quicly | +------------------+----------------+--------------------+ | Google Cloud CDN | Yes | Enabled by default | +------------------+----------------+--------------------+
Server support
+-----------+--------------------+--------------------+ | Server | Version | Notes | +-----------+--------------------+--------------------+ | Nginx | 1.25+ | Experimental QUIC | | | | module, mainline | | | | since 2023 | +-----------+--------------------+--------------------+ | LiteSpeed | 5.4+ | Early adopter, | | | | production QUIC | | | | since 2020 | +-----------+--------------------+--------------------+ | Caddy | 2.6+ | Built on quic-go, | | | | enabled by default | +-----------+--------------------+--------------------+ | IIS | Windows Server | MsQuic library, | | | 2022+ | kernel-mode QUIC | +-----------+--------------------+--------------------+ | H2O | 2.3+ | Powers Fastly edge | +-----------+--------------------+--------------------+
Challenges
HTTP/3 is not without operational friction.
UDP blocking. Some enterprise firewalls and corporate networks block UDP traffic on port 443 entirely. Browsers handle this with a fallback strategy: attempt QUIC, and if no response arrives within approximately 300ms, fall back to TCP and HTTP/2. The user doesn’t notice, but the first connection is slower.
Middlebox interference. Stateful firewalls that track QUIC connections impose CPU overhead on the middlebox. Unlike TCP, where the kernel handles state tracking efficiently, QUIC’s encrypted headers mean middleboxes can’t inspect or manipulate connection state. Some respond by blocking QUIC entirely.
CPU overhead. User-space packet processing costs roughly 2x the CPU of kernel-space TCP for the same throughput. QUIC encrypts nearly everything, including most header fields and all payload data, and processes it all outside the kernel.
Mitigation in progress. Linux kernel UDP Generic Segmentation Offload (GSO) and Generic Receive Offload (GRO) reduce the per-packet syscall overhead. Hardware vendors are working on QUIC-aware offload engines. Google’s QUICHE library uses sendmmsg/recvmmsg to batch syscalls. The gap is narrowing but not yet closed.
What comes next
The QUIC ecosystem is expanding beyond basic HTTP request-response.
QUIC v2 (RFC 9369, 2023). Updates the packet protection mechanisms and changes the initial salt used for packet encryption. The primary motivation is preventing ossification — if every QUIC implementation uses the same initial bytes, middleboxes will start pattern-matching on them. QUIC v2 changes those bytes to keep the wire format fluid.
Multipath QUIC (RFC 9443, 2024). Allows a single QUIC connection to send data over multiple network paths simultaneously. Your phone can use WiFi and cellular at the same time, with the QUIC stack scheduling packets across both paths based on available bandwidth and latency. This is connection migration taken to its logical conclusion.
WebTransport. A browser API for bidirectional, low-latency transport built on top of HTTP/3 and QUIC. Supports both reliable streams and unreliable datagrams. Reached Baseline status in March 2026, meaning it is available across all major browsers. WebTransport is the replacement for WebSocket in scenarios that need UDP-like semantics or multiple concurrent streams.
Media over QUIC (MOQ). A new IETF protocol for live media delivery with sub-second latency. Uses QUIC’s stream multiplexing to deliver audio, video, and data tracks independently. At NAB 2026, 11 vendors demonstrated interoperable MOQ implementations. This is the protocol positioned to replace RTMP for live streaming.
DNS over QUIC (RFC 9250). Encrypts DNS queries over a persistent QUIC connection. Lower latency than DNS over HTTPS (fewer round trips) and stronger privacy than DNS over TLS (connection migration, 0-RTT resumption).
There is no HTTP/4 on the horizon. The IETF’s focus is on extending HTTP/3 and the QUIC transport layer rather than creating a new HTTP version. The extensibility is built in: QUIC frames, HTTP/3 frames, and QUIC transport parameters can all be extended without a version bump.
RFC reference
+----------+--------------------+----------------+ | RFC | Title | Date | +----------+--------------------+----------------+ | RFC 9000 | QUIC: A UDP-Based | May 2021 | | | Multiplexed and | | | | Secure Transport | | +----------+--------------------+----------------+ | RFC 9001 | Using TLS to | May 2021 | | | Secure QUIC | | +----------+--------------------+----------------+ | RFC 9002 | QUIC Loss | May 2021 | | | Detection and | | | | Congestion Control | | +----------+--------------------+----------------+ | RFC 9114 | HTTP/3 | June 2022 | +----------+--------------------+----------------+ | RFC 9204 | QPACK: Field | June 2022 | | | Compression for | | | | HTTP/3 | | +----------+--------------------+----------------+ | RFC 9218 | Extensible | June 2022 | | | Prioritization | | | | Scheme for HTTP | | +----------+--------------------+----------------+ | RFC 9250 | DNS over Dedicated | May 2022 | | | QUIC Connections | | +----------+--------------------+----------------+ | RFC 9312 | Manageability of | September 2022 | | | the QUIC Transport | | | | Protocol | | +----------+--------------------+----------------+ | RFC 9369 | QUIC Version 2 | May 2023 | +----------+--------------------+----------------+ | RFC 9443 | Multiplexing | July 2024 | | | Scheme Updates for | | | | QUIC | | +----------+--------------------+----------------+ | RFC 8470 | Using Early Data | September 2018 | | | in HTTP (425 Too | | | | Early) | | +----------+--------------------+----------------+
This post is part of a series on HTTP. See HTTP/1.0 and HTTP/1.1 for where it started, and HTTP/2 for the binary framing revolution that set the stage for everything above.