Skip to content

HTTP status code · Informational (1xx)

101 Switching Protocols

101 Switching Protocols means the server accepted the client's Upgrade request and the connection now speaks a different protocol. In practice you see it every time a browser opens a WebSocket: the 101 is the successful end of the handshake, not an error.

Facts about this status code
Class1xx, Informational
Defined inRFC 9110 §15.2.2
Cacheable by defaultNo
Safe to retryNot applicable; after a 101 the connection speaks the new protocol
Relevant headers
  • Upgrade: required in the 101; names the protocol now in effect, e.g. websocket
  • Connection: must list Upgrade so intermediaries know the header is hop-by-hop
  • Sec-WebSocket-Accept: WebSocket only: proves the server read the client key (RFC 6455)

What 101 means

RFC 9110, section 15.2.2, requires the server to include an Upgrade header naming the protocol that takes over. For a WebSocket (RFC 6455) the browser sends Upgrade: websocket, Connection: Upgrade and a random Sec-WebSocket-Key; the server answers 101 with Sec-WebSocket-Accept, a hash of that key. After the blank line that ends the 101, no more HTTP travels on that TCP connection.

The mechanism belongs to HTTP/1.1. HTTP/2 does not use 101 at all (RFC 9113, section 8.6), and WebSockets over HTTP/2 use an extended CONNECT request instead (RFC 8441). That is why a reverse proxy has to speak HTTP/1.1 to the backend for the upgrade to get through.

When to use it

  • Let your WebSocket library send it; hand-writing the handshake means computing Sec-WebSocket-Accept yourself and is easy to get wrong.
  • Put the WebSocket endpoint on its own path (/ws) so proxy rules for the upgrade apply only there.

Common causes

If you are visiting the site

  • A chat, live score or dashboard never updates: a corporate proxy, VPN or antivirus is blocking WebSocket upgrades on your network.

If you run the server

  • The handshake returns 200, 400 or 404 instead of 101: nginx or another proxy dropped the Upgrade and Connection headers, which are hop-by-hop and not forwarded by default.
  • The socket opens with 101 and dies after exactly 60 seconds of silence: nginx closes idle proxied connections after proxy_read_timeout, which defaults to 60s.

How to fix it

If you are visiting the site

  • Try another network or disable the VPN or HTTPS inspection feature of your antivirus, then reload the page.

If you run the server

  • In nginx set proxy_http_version 1.1 and pass Upgrade and Connection explicitly, as in the example below.
  • Send WebSocket ping frames every 20 to 30 seconds, or raise proxy_read_timeout for the /ws location.

How to send 101

Next.js route handlers cannot take over the socket, so they cannot answer an upgrade; run the WebSocket server as a separate process or a custom server.

Express (Node.js)
import { WebSocketServer } from 'ws';

const server = app.listen(3000);
const wss = new WebSocketServer({ noServer: true });

// ws writes "101 Switching Protocols" and Sec-WebSocket-Accept for you
server.on('upgrade', (req, socket, head) => {
  if (req.url !== '/ws') return socket.destroy();
  wss.handleUpgrade(req, socket, head, (ws) => {
    ws.send('connected');
  });
});
Go net/http
// github.com/gorilla/websocket
var upgrader = websocket.Upgrader{}

mux.HandleFunc("GET /ws", func(w http.ResponseWriter, r *http.Request) {
	conn, err := upgrader.Upgrade(w, r, nil) // sends 101 Switching Protocols
	if err != nil {
		return // Upgrade already wrote an HTTP error response
	}
	defer conn.Close()
	conn.WriteMessage(websocket.TextMessage, []byte("connected"))
})
Python FastAPI
from fastapi import FastAPI, WebSocket

app = FastAPI()

@app.websocket("/ws")
async def ws_endpoint(websocket: WebSocket):
    await websocket.accept()  # the server sends 101 Switching Protocols
    await websocket.send_text("connected")
Nginx
location /ws {
  proxy_pass http://app;
  proxy_http_version 1.1;               # 101 only exists in HTTP/1.1
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "upgrade";
  proxy_read_timeout 1h;                # default 60s kills idle sockets
}

Commonly confused with

101 vs 426
426 Upgrade Required is the server demanding a protocol change; 101 is the server agreeing to one the client asked for.
101 vs 200
A 200 to a WebSocket handshake means something ignored the Upgrade header and served a normal page, so the socket fails.

Frequently asked questions

Is status 101 an error in the browser Network tab?
No. A WebSocket row with status 101 means the handshake succeeded. The messages that follow appear under that row, in the Messages or Response tab depending on the browser.
Why does my WebSocket get 200 or 400 instead of 101?
Usually a reverse proxy is not forwarding the Upgrade and Connection headers, so the backend sees a plain GET. In nginx add proxy_http_version 1.1 and the two proxy_set_header lines for Upgrade and Connection.
Does HTTP/2 use 101 Switching Protocols?
No. RFC 9113 says HTTP/2 does not use 101. WebSockets over HTTP/2 are opened with an extended CONNECT request defined in RFC 8441, and many servers simply keep WebSockets on HTTP/1.1.

Last reviewed by Arielton Oberek.