Switching protocols mid-connection
Modern HTTP can negotiate a better protocol — HTTP/2, HTTP/3 or WebSocket —
after a connection starts. The Upgrade mechanism switches the current
connection in place and returns 101 Switching Protocols, while Alt-Svc
points the client at an alternative endpoint to use on future requests. This
reference covers those headers plus the TLS ALPN extension that actually drives
h2/h3 selection in browsers, with a parser for any Alt-Svc value.
When each mechanism is used
| Mechanism | When it applies | Protocol examples |
|---|---|---|
| TLS ALPN | During TLS handshake — negotiates protocol before first byte | HTTP/2, HTTP/3 |
Upgrade header | On an existing clear-text connection; switches in place | WebSocket, h2c (cleartext HTTP/2) |
Alt-Svc header | Advertises a better endpoint for future connections | HTTP/3 via QUIC |
101 Switching Protocols | Server response confirming an Upgrade | WebSocket |
How it works
An Alt-Svc value is a comma-separated list of alternative services, each with
a protocol id, an authority and optional parameters:
Alt-Svc: h3=":443"; ma=86400; persist=1, h2="alt.example.com:443"; ma=3600
Here h3 (HTTP/3 over QUIC) is offered on port 443 of the same host for one day
and persisted across network changes, while h2 points to a different host. The
parser splits each entry and reads its ma (max-age) and persist flag. The
classic Upgrade flow is different — it is hop-by-hop and switches the live
connection:
GET /chat HTTP/1.1
Connection: Upgrade
Upgrade: websocket
→ HTTP/1.1 101 Switching Protocols
In browsers, HTTP/2 and HTTP/3 are chosen during the TLS handshake via ALPN, so
Upgrade survives mainly for WebSocket and Alt-Svc for steering to QUIC.
How browsers adopt HTTP/3 via Alt-Svc
A typical HTTP/3 advertisement looks like this in the response from a server that supports both HTTP/2 (current connection) and HTTP/3 (preferred future):
HTTP/2 200 OK
Alt-Svc: h3=":443"; ma=86400
The browser receives this on an HTTP/2 connection, notes the advertisement, and on its next request to this origin tries QUIC/HTTP/3 on port 443. If the QUIC connection succeeds, it switches and caches the result for the ma duration (86400 seconds = one day). If QUIC fails (firewall, middlebox), the browser falls back to HTTP/2 and suppresses the alternative for a while.
The persist=1 flag asks the browser to keep the alternative across network changes (for example, Wi-Fi to cellular handover). Without it, the cache is tied to the current network interface.
WebSocket upgrade flow
The WebSocket protocol repurposes HTTP/1.1’s Upgrade mechanism. The client signals intent by sending two required headers:
GET /socket HTTP/1.1
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
The server confirms by echoing Upgrade: websocket and returning 101 Switching Protocols. After that, the connection is no longer HTTP — it is a bidirectional WebSocket stream. The Connection: Upgrade header is hop-by-hop and must not be forwarded by proxies, which is why WebSocket connections require Connection: Upgrade rather than using a different mechanism.
Tips
Connection: Upgrademust accompanyUpgrade, or proxies will strip it and the switch will fail.- An empty host in
Alt-Svc(e.g.h3=":443") means the same host on that port — the colon is required. madefaults to 24 hours;persist=1keeps the alternative cached across network changes.- Cleartext
h2cupgrades are essentially unused on the public web — browsers negotiate HTTP/2 and HTTP/3 via TLS ALPN instead. - Use
Alt-Svc: clearto tell clients to forget any advertised alternatives (useful during a migration rollback).