< HTTP/1.1 101 Switching Protocols101 Switching Protocols
The server is switching to a different protocol as requested by the client. Learn about WebSocket upgrades and protocol negotiation.
- Cacheable
- n/a (interim or validation response)
- Client action
- Speak the new protocol
- Usually sent by
- Origin server (WebSocket, h2c upgrades)
- Spec
- RFC 9110 §15.2.2
On this page
TL;DR: Server agrees to switch protocols (usually HTTP to WebSocket). Connection changes to new protocol after this response.
What is 101 Switching Protocols?
A 101 Switching Protocols status code means the server agrees to switch to a different protocol that the client requested via the Upgrade header. Think of it like switching from talking on the phone to having a video call—you’re changing the communication method mid-conversation.
This is most commonly used to upgrade from HTTP to WebSocket for real-time bidirectional communication.
When Does This Happen?
You’ll see a 101 Switching Protocols response in these common situations:
1. WebSocket Connection Upgrade
Client wants to establish WebSocket for real-time chat
HTTP → WebSocket
2. HTTP/2 Upgrade (Less Common)
Client requests HTTP/2 over cleartext
HTTP/1.1 → HTTP/2
3. Custom Protocol Upgrade
Application-specific protocol negotiation
HTTP → Custom bidirectional protocol
Example Responses
WebSocket Upgrade Request:
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
101 Switching Protocols Response:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Real-World Example
Imagine you’re building a real-time chat application:
Client Initiates WebSocket Upgrade:
GET /ws/chat HTTP/1.1
Host: chat.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: https://example.com
Server Accepts Upgrade:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
After this exchange, the connection is now a WebSocket. Both client and server can send messages at any time without the request/response pattern of HTTP.
101 vs Other Status Codes
| Code | Meaning | Protocol Change | Use Case |
|---|---|---|---|
| 101 | Switching protocols | Yes | WebSocket, protocol upgrades |
| 100 | Continue | No | Large request body validation |
| 200 | OK | No | Standard successful response |
| 426 | Upgrade Required | No (server demands it) | Force protocol upgrade |
Important Characteristics
Permanent Protocol Switch:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
After 101, the connection no longer uses HTTP. All future data follows the new protocol.
Must Include Upgrade Header:
# Client MUST send:
Upgrade: websocket
Connection: Upgrade
# Server MUST echo:
Upgrade: websocket
Connection: Upgrade
No Response Body: The 101 response has no body. After the headers, the connection immediately switches to the new protocol.
Common Mistakes
❌ Using 101 without Upgrade header
HTTP/1.1 101 Switching Protocols
# Missing Upgrade header!
❌ Sending body with 101 response
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
{"message": "WebSocket ready"} ← Wrong! No body allowed
❌ Not validating WebSocket handshake
// ❌ Bad: Accept any upgrade request
app.get('/ws', (req, res) => {
res.status(101).end()
})
✅ Correct WebSocket upgrade
// ✅ Good: Proper WebSocket handshake
const crypto = require('crypto')
app.get('/ws', (req, res) => {
const key = req.headers['sec-websocket-key']
const acceptKey = crypto
.createHash('sha1')
.update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')
.digest('base64')
res.writeHead(101, {
Upgrade: 'websocket',
Connection: 'Upgrade',
'Sec-WebSocket-Accept': acceptKey
})
})
Getting 101 Switching Protocols right
Validate Upgrade Requests:
app.get('/ws', (req, res) => {
// Check required headers
if (req.headers.upgrade?.toLowerCase() !== 'websocket') {
return res.status(400).send('WebSocket upgrade required')
}
if (!req.headers['sec-websocket-key']) {
return res.status(400).send('WebSocket key required')
}
// Proceed with upgrade...
})
Use WebSocket Libraries:
// Use established libraries instead of manual implementation
const WebSocket = require('ws')
const wss = new WebSocket.Server({
server: httpServer,
path: '/ws'
})
wss.on('connection', (ws) => {
ws.on('message', (data) => {
console.log('received:', data)
})
ws.send('Welcome to WebSocket!')
})
Handle Protocol Negotiation:
// Support multiple sub-protocols
app.get('/ws', (req, res) => {
const requestedProtocols = req.headers['sec-websocket-protocol']?.split(',')
const supportedProtocols = ['chat', 'notifications']
const protocol = requestedProtocols?.find((p) => supportedProtocols.includes(p.trim()))
if (!protocol) {
return res.status(400).send('No supported protocol')
}
// Include selected protocol in response
res.setHeader('Sec-WebSocket-Protocol', protocol.trim())
// ... continue with upgrade
})
Implementation Examples
Node.js with ws library:
const http = require('http')
const WebSocket = require('ws')
const server = http.createServer()
const wss = new WebSocket.Server({ server })
wss.on('connection', (ws, req) => {
console.log('Client connected from:', req.socket.remoteAddress)
ws.on('message', (message) => {
console.log('Received:', message)
ws.send(`Echo: ${message}`)
})
ws.on('close', () => {
console.log('Client disconnected')
})
})
server.listen(3000)
Python with websockets:
import asyncio
import websockets
async def handler(websocket, path):
async for message in websocket:
print(f"Received: {message}")
await websocket.send(f"Echo: {message}")
start_server = websockets.serve(handler, "localhost", 3000)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
Browser JavaScript:
const ws = new WebSocket('ws://localhost:3000/chat')
ws.onopen = () => {
console.log('Connected')
ws.send('Hello Server!')
}
ws.onmessage = (event) => {
console.log('Received:', event.data)
}
ws.onerror = (error) => {
console.error('WebSocket error:', error)
}
ws.onclose = () => {
console.log('Disconnected')
}
Try It Yourself
Visit our request builder to see protocol upgrades:
- Open browser DevTools Network tab
- Visit a WebSocket demo page
- Watch the initial HTTP request
- See the 101 Switching Protocols response
- Observe WebSocket frames in the WS tab
Try it with curl
Send a WebSocket handshake by hand. -N disables output buffering, --http1.1 avoids HTTP/2 (which has no Upgrade), and -m 5 stops curl after 5 seconds because the connection stays open after the switch. The key below is the sample from RFC 6455.
curl -i -N --http1.1 -m 5 https://api.example.com/socket \
-H 'Connection: Upgrade' \
-H 'Upgrade: websocket' \
-H 'Sec-WebSocket-Version: 13' \
-H 'Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ=='
Example output (illustrative, not captured from a real server):
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
curl cannot speak WebSocket frames over this connection, so it prints nothing further and then times out. A 400 or 426 here means the server rejected the handshake or the endpoint is not a WebSocket route.
Related Status Codes
- 100 Continue - Interim response for large uploads
- 426 Upgrade Required - Server requires protocol upgrade
- 200 OK - Standard successful HTTP response
Related Headers
- Upgrade - Specifies protocol to switch to
- Connection - Must be “Upgrade” for protocol switching
- Sec-WebSocket-Key - Client’s WebSocket handshake key
- Sec-WebSocket-Accept - Server’s WebSocket handshake response
See also the comparison SSE vs WebSockets vs long polling: choosing a realtime transport, with proxy buffering and HTTP/2 caveats.
Frequently asked questions
What does 101 Switching Protocols mean?
A 101 response means the server agrees to switch to a different protocol requested by the client via the Upgrade header. It is most commonly used for upgrading HTTP connections to WebSocket.
How does WebSocket upgrade work?
The client sends an HTTP request with Upgrade: websocket header. If the server supports it, it responds with 101 Switching Protocols and the connection becomes a WebSocket connection.
What protocols can be upgraded with 101?
Common upgrades include HTTP to WebSocket, HTTP/1.1 to HTTP/2, and HTTP to TLS. The Upgrade header specifies the target protocol.
Is 101 used for HTTPS?
No, HTTPS uses TLS which is established before HTTP. The 101 status is for application-layer protocol upgrades like WebSocket, not transport-layer security.
Sources
Related
100 Continue
The server received the request headers and the client should proceed to send the body. Learn when and how to use 100 Continue for efficient large uploads.
102 Processing
The server has accepted the request and is processing it, but no response is available yet. Learn about this WebDAV status code for long-running operations.
WebSockets over HTTP: Handshakes, Proxies and Auth
Trace a WebSocket HTTP handshake, verify Sec-WebSocket-Accept, configure nginx, secure browser authentication, and debug idle disconnects and close codes.
426 Upgrade Required
The server refuses to perform the request using the current protocol and requires the client to upgrade to a different protocol.