HTTP 426 is Upgrade Required: the server refuses to perform the request using the current protocol, but might after the client upgrades to a different one (RFC 9110 section 15.5.22). It must carry an Upgrade header naming the required protocols, in order of preference, and an Upgrade option in Connection (section 7.8).
The exchange
RFC 9110’s example:
HTTP/1.1 426 Upgrade Required
Upgrade: HTTP/3.0
Connection: Upgrade
Content-Length: 53
Content-Type: text/plain
This service requires use of the HTTP/3.0 protocol.
Treat it as an illustration. HTTP/3 runs over QUIC, and RFC 9110 says Upgrade can’t switch the underlying transport, so a real client finds HTTP/3 through Alt-Svc instead.
Where you’ll see it
- WebSocket servers answering plain HTTP. The Node
wslibrary’s standalone server answers every request that isn’t a WebSocket handshake with426 Upgrade Required, though without theUpgrade: websocketheader RFC 9110 requires. - WebSocket version mismatches. RFC 6455 suggests 426 with a
Sec-WebSocket-Versionheader listing the versions the server speaks, though its own example uses 400. - RFC 2817’s in-band TLS upgrade,
Upgrade: TLS/1.0on a plain connection, which introduced the code. Browsers never implemented it, and Apache httpd removed its support (SSLEngine optional) in 2.4.64 after CVE-2025-49812.
It can’t force HTTPS
A 426 doesn’t move a browser to HTTPS: the browser shows the body and stops. Redirect with a 301 or 308 to the https:// URL, and send Strict-Transport-Security so the browser goes straight to HTTPS next time.
426, 101 or 505
the server wants another protocol before it will answer 426 Upgrade Required
the server agreed to the client's Upgrade and switched 101 Switching Protocols
the server won't speak the request's major HTTP version 505 HTTP Version Not Supported
Gotchas
- HTTP/1.1 only. HTTP/2 forbids the
Upgradeheader (RFC 9113 section 8.2.2), so a 426 sent over HTTP/2 can’t name what it wants. - An API version isn’t a protocol. Retiring
/v1is a 410 Gone or a documented error, not a 426: noUpgradevalue means “use v2”. - Clients don’t act on it. Most HTTP libraries report a 426 as a failure; only one that speaks the named protocol can upgrade and retry.
- Caching. 426 isn’t heuristically cacheable.
A WebSocket-only endpoint in Node, answering ordinary requests properly:
server.on('request', (req, res) => {
res.writeHead(426, { Upgrade: 'websocket', Connection: 'Upgrade', 'Content-Type': 'text/plain' });
res.end('This endpoint only speaks WebSocket.\n');
});
Search 101 426 in the tool below to compare the two.