HTTP 426 Upgrade Required

Upgrade Required

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 ws library’s standalone server answers every request that isn’t a WebSocket handshake with 426 Upgrade Required, though without the Upgrade: websocket header RFC 9110 requires.
  • WebSocket version mismatches. RFC 6455 suggests 426 with a Sec-WebSocket-Version header listing the versions the server speaks, though its own example uses 400.
  • RFC 2817’s in-band TLS upgrade, Upgrade: TLS/1.0 on 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 Upgrade header (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 /v1 is a 410 Gone or a documented error, not a 426: no Upgrade value 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.

Try it in the HTTP Status Codes

426 Upgrade Required

  1. 426Upgrade Required4xx Client error

    The server refuses the request at the current protocol and asks the client to switch, naming what it wants in an Upgrade header.

    When to use it

    A resource the server will only serve over another protocol, such as a WebSocket endpoint that receives a plain GET; the Upgrade header names the protocol it wants.

    Common mistakes

    Using it to send clients to HTTPS, which browsers do not act on — that is a 301 or a 308 redirect — and expecting an ordinary client to retry by itself: it has to understand the upgrade, so most simply report the failure.

    Not cacheable by defaultRFC 9110

Every code, by class

Codes marked unofficial come from one server’s own convention — nginx, Cloudflare, cPanel, Microsoft — and are not in the IANA registry.

Runs in your browser. Nothing you enter is sent anywhere.