HTTP 426 Upgrade Required
Quick reference
| Code | 426 |
|---|---|
| Name | Upgrade Required |
| Category | 4xx Client Error |
| Spec | RFC 9110 ยง15.5.27 |
| Required header | Upgrade: in response |
What 426 means
HTTP 426 Upgrade Required tells the client that the server will not process this request over the current protocol, and the client must switch to the protocol listed in the response's Upgrade: header. RFC 9110 ยง15.5.27 requires the response to include an Upgrade: header specifying the required protocol (or ordered list of protocols) and a Connection: Upgrade header.
The most common real-world use case is WebSocket-only endpoints. A WebSocket server endpoint at /ws requires the client to perform the HTTP/1.1 Upgrade handshake โ sending Upgrade: websocket and Connection: Upgrade in the request. If a regular HTTP GET arrives at that endpoint without those headers, the server returns 426 to signal the required upgrade.
A second use case is enforcing HTTPS. An HTTP server that refuses to handle requests over plain HTTP can return 426 with Upgrade: TLS/1.3, HTTP/1.1 to indicate the client must reconnect over TLS. This is less common than a 301 redirect to the HTTPS URL, but more explicit when the server wants to refuse processing entirely rather than redirect.
The 426 โ 101 upgrade flow
The complete WebSocket upgrade sequence shows how 426 fits into the negotiation:
# Client sends a plain GET (no upgrade headers): GET /ws/chat HTTP/1.1 Host: api.example.com # Server requires WebSocket upgrade: HTTP/1.1 426 Upgrade Required Upgrade: websocket Connection: Upgrade Content-Type: text/plain This endpoint requires a WebSocket connection. Use Upgrade: websocket and Connection: Upgrade headers. # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ # Client retries with WebSocket upgrade headers: GET /ws/chat HTTP/1.1 Host: api.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Sec-WebSocket-Version: 13 # Server accepts the upgrade: HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
After the 101, the connection transitions to the WebSocket protocol and is no longer HTTP. Frames are sent and received using the WebSocket framing format.
Returning 426 from a server
Node.js (http module) โ WebSocket-only endpoint:
const http = require('http');
const server = http.createServer((req, res) => {
if (req.url === '/ws') {
if (!req.headers.upgrade || req.headers.upgrade.toLowerCase() !== 'websocket') {
res.writeHead(426, {
'Upgrade': 'websocket',
'Connection': 'Upgrade',
'Content-Type': 'application/json'
});
res.end(JSON.stringify({
error: 'upgrade_required',
message: 'This endpoint requires a WebSocket connection'
}));
return;
}
// handle WebSocket upgrade...
}
});
nginx โ require HTTPS with 426:
server {
listen 80;
server_name api.example.com;
location / {
return 426 "TLS upgrade required";
add_header Upgrade "TLS/1.3, HTTP/1.1" always;
add_header Connection "Upgrade" always;
}
}
Note: Most deployments prefer a 301 redirect to HTTPS over a 426, since browsers and HTTP clients handle redirects automatically. Use 426 only when clients must explicitly handle the upgrade rather than being silently redirected.
Client-side fix
When a client receives 426, it must read the Upgrade: header value and reconnect using the specified protocol. For WebSocket upgrades, this means switching from fetch() or XMLHttpRequest to the WebSocket constructor:
// Wrong: sending a plain HTTP request to a WebSocket-only endpoint
const res = await fetch('https://api.example.com/ws/chat');
// Returns 426
// Right: use WebSocket
const ws = new WebSocket('wss://api.example.com/ws/chat');
ws.onopen = () => console.log('connected');
ws.onmessage = (event) => console.log(event.data);
For HTTP-to-HTTPS upgrade (rare), update the URL scheme from http:// to https:// and reconnect.
426 vs related codes
| Code | Meaning | Difference from 426 |
|---|---|---|
| 426 | Protocol upgrade required | โ |
| 101 Switching Protocols | Upgrade accepted, switching now | Success response after a valid upgrade request |
| 301 Moved Permanently | Redirect to new URL | URL change, not protocol change |
| 403 Forbidden | Access denied | Permission issue, not a protocol requirement |
Frequently asked questions
Is 426 the right code for "please use HTTPS"?
It is technically correct but rarely used that way in practice. Most servers return a 301 redirect to the HTTPS URL instead, because browsers and HTTP clients follow 301 redirects automatically. A 426 requires the client to explicitly handle the upgrade, which most HTTP clients do not do for plain HTTP-to-HTTPS transitions. Use 301 for HTTPS enforcement unless you have a specific reason to prevent silent redirection.
Does the Upgrade header need to match exactly?
The Upgrade: header value should be a registered protocol token. The IANA protocol registry includes values like websocket, HTTP/2.0, TLS/1.3. The casing convention is lowercase for WebSocket (websocket) and mixed case for others. Clients should match the value case-insensitively.
Can a proxy return 426?
Yes. A proxy that requires TLS between the client and itself can return 426 to inform the client to reconnect over an encrypted channel. This is distinct from a transparent proxy, which would not modify the response.
What happens if the client ignores 426?
The connection stays on the current protocol and no data is exchanged on the requested endpoint. For WebSocket endpoints, subsequent requests without upgrade headers will continue to receive 426 until the client uses the correct protocol.
Related guides
HTTP 101 ยท HTTP 301 ยท HTTP 400 ยท HTTP 425 ยท HTTP 510
Client Errors Hub ยท All Guides ยท Home