HTTP status codes / 101
101 Switching Protocols — HTTP Status Code
101 Switching Protocols means the server accepted the client's Upgrade request and the connection now speaks a different protocol. Almost every real-world 101 is a WebSocket handshake over HTTP/1.1. After the 101, the connection is no longer carrying ordinary HTTP responses.
101 Switching Protocols means the server has agreed to stop talking HTTP on this connection and start talking the protocol the client asked for. In practice that is nearly always WebSocket: the browser opens an HTTP/1.1 request with Upgrade: websocket, and a 101 response turns the same TCP connection into a two-way message channel.
What 101 means
RFC 9110 (Section 15.2.2) defines 101 as the server understanding and accepting a request, made through the Upgrade header field (Section 7.8), to change the application protocol on the current connection. The server must include its own Upgrade header saying which protocol takes over once the 101 response ends.
Two points make 101 different from every other code:
- It is interim, but nothing HTTP follows. Other 1xx responses are followed by a final HTTP status. After a 101, the bytes on the wire belong to the new protocol, so the "final response" is whatever that protocol defines.
- The client has to ask. A server cannot spring 101 on a client. It only answers an explicit
Upgraderequest, and it may ignore the request and answer normally if switching has no benefit.
RFC 9113 states that HTTP/2 does not support 101 at all, because a multiplexed connection cannot be handed over to another protocol. WebSocket over HTTP/2 uses extended CONNECT (RFC 8441) instead.
When you see it
- WebSocket handshakes. Chat widgets, live dashboards, multiplayer games and development servers with hot reload all open WebSocket connections. The browser's network panel lists these requests with status 101.
- Real-time frameworks. Libraries such as Socket.IO try a WebSocket upgrade, and a successful upgrade shows up as 101.
- Upgrade from cleartext HTTP/1.1 to HTTP/2 (
h2c). The original HTTP/2 specification allowed this, but it was never widely deployed and RFC 9113 deprecates it. You are unlikely to meet it.
A typical successful WebSocket exchange looks like this:
GET /socket HTTP/1.1
Host: app.example.com
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: ...
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Accept: ...
Why an expected 101 does not arrive
When a WebSocket fails, the interesting question is what came back instead of 101:
- A 200 page. The upgrade headers were stripped somewhere, so the request was served as normal HTTP. In nginx, a WebSocket location needs
proxy_http_version 1.1and explicitUpgradeandConnectionheaders set withproxy_set_header. - 404 or 400. The path is wrong, or the app's WebSocket handler rejected the handshake (for example a missing or invalid
Sec-WebSocket-Key). - 401 or 403. The socket endpoint requires a session cookie or token that the client did not send, or an origin check failed.
- A connection that opens, then drops. The 101 arrived, but an idle timeout on a load balancer or proxy closes the socket later. Sending periodic ping frames keeps it alive.
How to check it
curl can send a WebSocket handshake by hand. Recent curl versions also accept ws:// and wss:// URLs, but the manual version works everywhere:
curl -sv -o /dev/null --http1.1 \
-H "Connection: Upgrade" -H "Upgrade: websocket" \
-H "Sec-WebSocket-Version: 13" \
-H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
https://app.example.com/socket
Look for < HTTP/1.1 101 Switching Protocols in the output. curl will then sit on the open connection; press Ctrl+C to stop. --http1.1 matters, because over HTTP/2 the upgrade does not apply.
What it means for uptime monitoring
An HTTP uptime check is not a WebSocket client. PingRobot's checker sends an ordinary GET without an Upgrade header, so a server has no reason to answer it with 101; it judges the final HTTP response, treating 200 to 399 as up and anything else as down.
If you point a monitor at a WebSocket-only path, you will usually get whatever the server returns for a plain GET there: often 400, 404 or 426, which counts as down. Better options:
- Monitor the page or API that serves the app, and add a keyword check for text that only appears when it rendered correctly.
- Expose a small HTTP health route on the same service that confirms the socket server is accepting connections.
- Use a TCP port monitor if the socket server listens on its own port.
Related codes
- 100 Continue — the other interim code from RFC 9110
- 103 Early Hints — interim headers before a final response
- 400 Bad Request — a common reply to a malformed handshake
- 401 Unauthorized and 403 Forbidden — socket endpoints that need auth
- 505 HTTP Version Not Supported — protocol version refused outright
Start monitoring free — 10 monitors, no credit card.
Frequently asked questions
Is 101 Switching Protocols a success or an error?
It is a success for the handshake. The server understood the Upgrade header and agreed to switch. Problems start only if the client expected 101 and got something else, such as 400, 404 or 426.
Why does my WebSocket connection get 200 instead of 101?
Usually a proxy or CDN in front of the app is not passing the Upgrade and Connection headers through, so the request reaches the app as a normal GET. Check the proxy's WebSocket settings.
Does HTTP/2 use 101?
No. RFC 9113 says HTTP/2 does not support 101. WebSockets over HTTP/2 use an extended CONNECT method defined in RFC 8441 instead.