HTTP/3 is faster on slow, laggy connections because it uses UDP instead of TCP, and it handles multiple streams of data much more intelligently.
Let’s see it in action. Imagine you’re trying to load a webpage with several resources (images, scripts, CSS) over a satellite link.
# Simulate a high-latency, lossy connection (e.g., 500ms RTT, 2% packet loss)
tc qdisc add dev eth0 root netem delay 500ms loss 2%
With HTTP/1.1 or HTTP/2 over TCP, each request for a resource might involve a full TCP handshake (SYN, SYN-ACK, ACK) which takes 3 round trips. If the connection is lossy, retransmissions add even more delay. Even with HTTP/2’s multiplexing, head-of-line blocking at the TCP layer means one lost packet for any stream can stall all streams.
Now, let’s switch to HTTP/3.
The Core Idea: QUIC on UDP
HTTP/3 runs over a transport protocol called QUIC, which is built on top of UDP. UDP is a "dumb" protocol – it just sends packets. All the intelligence for reliability, ordering, and flow control that TCP provides is now implemented within QUIC itself, at the application layer.
Why UDP is Key for High Latency
-
No TCP Handshake: QUIC establishes a connection with a single round trip (0-RTT or 1-RTT depending on whether it’s a new or resumed connection), drastically cutting down the initial setup time on a high-latency link. A 500ms RTT connection means a TCP handshake takes at least 1.5 seconds before any actual data is sent. QUIC can do this in 500ms or less.
-
No Head-of-Line Blocking (at the Transport Layer): This is the killer feature. In TCP, if packet #5 for stream A is lost, then packet #6 for stream B (which arrived successfully) must wait until packet #5 is retransmitted and received. This is TCP head-of-line blocking. QUIC, being stream-oriented at the application level and running over UDP, allows independent streams. If a packet for stream A is lost, only stream A is affected; stream B can continue delivering its data.
Let’s look at a simplified QUIC packet structure (this is conceptual, actual packets are more complex):
+-------------------------------------------------------------------+
| UDP Header (Source Port, Dest Port, Length, Checksum) |
+-------------------------------------------------------------------+
| QUIC Packet Header (Connection ID, Packet Number, Flags) |
+-------------------------------------------------------------------+
| QUIC Frame 1: STREAM (Stream ID, Offset, Length, Data...) |
+-------------------------------------------------------------------+
| QUIC Frame 2: STREAM (Stream ID, Offset, Length, Data...) |
+-------------------------------------------------------------------+
| QUIC Frame 3: ACK (Acknowledged Packet Numbers, etc.) |
+-------------------------------------------------------------------+
Notice how multiple STREAM frames can exist within a single QUIC packet. Each STREAM frame is tagged with a Stream ID. If a packet carrying STREAM frames for Stream ID = 5 is lost, but a later packet arrives with STREAM frames for Stream ID = 7, the receiver can process the data for Stream ID = 7 immediately.
Connection Migration
QUIC uses Connection IDs to identify connections, not the IP address and port tuple like TCP. This means if your device’s IP address changes (e.g., switching from Wi-Fi to cellular, or a mobile device moving between cell towers), the QUIC connection can persist. While not directly a performance boost on a fixed satellite link, it contributes to a more robust and seamless experience, preventing disruptive connection resets.
TLS 1.3 Integration
QUIC mandates TLS 1.3 for encryption and authentication. This integration is crucial:
- Faster Handshake: TLS 1.3 itself has a 0-RTT or 1-RTT handshake. When combined with QUIC’s 0-RTT or 1-RTT connection establishment, you get a very fast, encrypted connection setup.
- Forward Secrecy: TLS 1.3 provides strong security guarantees.
Consider the latency impact:
- TCP + TLS 1.2: 3 RTT for TCP handshake + 2 RTT for TLS handshake = 5 RTT before data.
- TCP + TLS 1.3: 3 RTT for TCP handshake + 1 RTT for TLS handshake = 4 RTT before data.
- QUIC (HTTP/3): 1 RTT for QUIC/TLS handshake = 1 RTT before data.
On a 500ms RTT link, this is the difference between 2.5 seconds of setup time versus 500 milliseconds.
The biggest benefit on a high-latency, lossy link like satellite is the elimination of transport-level head-of-line blocking. When a packet is lost, only the specific stream affected by that lost packet stalls. Other streams can continue to make progress. This means even if one image is slow to load due to a retransmission, the critical text and layout of the webpage can still be rendered quickly.
If you’re seeing "Maximum concurrent connections reached" errors after enabling HTTP/3, it’s because the client is now able to open many more streams concurrently over a single connection without performance degradation due to transport-level blocking.