522 Connection Timed Out
Server error response defined by developers.cloudflare.com.
Last updated July 27, 2026
Common causes at a glance
- A firewall DROP rule silently discarding traffic from Cloudflare IP ranges
- An overloaded origin whose listen backlog is full and dropping new SYNs
- A DNS A record pointing at an IP the origin no longer owns
- TCP keepalives disabled at the origin, so idle pooled connections die unnoticed
Reproduce it
curl -sS --connect-timeout 20 --resolve www.example.com:443:203.0.113.10 https://www.example.com/What 522 Connection Timed Out means
Cloudflare documents two distinct timeouts behind this one code. Before a connection is established, the origin has 19 seconds to return a SYN+ACK, across a retry backoff of 1, 1, 1, 1, 1, 2, 4, 8 seconds. After a connection exists, it has 90 seconds to acknowledge the resource request. Both windows are generous, so hitting either means something is badly wrong rather than merely slow.
The word to hold onto is silence. A DROP rule, a full
accept queue, a security group that never got the Cloudflare ranges, or a stale
A record all produce the same symptom: no answer. Compare
504, where a connection exists and the response is late.
There is no RFC
522 is unregistered. It is absent from the IANA HTTP Status Code Registry and defined solely by Cloudflare’s troubleshooting docs. Any client following RFC 9110 §15 treats an unrecognised 5xx as 500, so dashboards that bucket by class fold 522 into generic server errors and hide the signal you need. The more expensive consequence is diagnostic: the edge generates this page after its handshake attempt expires, so no request reached your application. Nothing appears in your access log, and that absence is confirmation rather than a dead end.
What actually causes it
Cloudflare names the blocked-IP case as the single most common
cause, and it recurs because the block is usually invisible to whoever set it.
A DROP rule produces no rejection, no client-side log entry, and
no symptom for traffic from anywhere else. Rate-limiting rules are worse: they
pass normal traffic and only start dropping once a data centre’s connection
volume crosses a threshold, so the 522 appears intermittently and correlates
with load rather than configuration. The stale A record is its own trap, since
the hostname resolves fine and points at a machine that belongs to somebody
else now.
How to debug it
The signature of 522 is a hang. Time the handshake at the origin IP and watch it run out rather than fail fast:
curl -sv --connect-timeout 20 --resolve www.example.com:443:203.0.113.10 \
https://www.example.com/ 2>&1 | grep -E 'Trying|Connected|timed out'
If that hangs from your laptop too, the block is not Cloudflare-specific and it
is an ordinary reachability problem. If your laptop connects fine and only
Cloudflare times out, the allowlist is the prime suspect: compare your rules
against the published Cloudflare ranges rather than the copy in
your runbook. Check ss -ltn for a saturated Recv-Q on
the listening socket too.
Working examples
curl
# 522 hangs; 521 fails immediately. Timing is the discriminator.
curl -sv --connect-timeout 20 \
--resolve www.example.com:443:203.0.113.10 \
https://www.example.com/ 2>&1 | grep -E 'Trying|Connected|timed out'
# Where the handshake time actually goes.
curl -s -o /dev/null \
-w 'dns=%{time_namelookup} connect=%{time_connect} total=%{time_total}\n' \
https://www.example.com/
Python (requests)
import socket, time
# Time a raw TCP handshake to the origin. A full timeout is the 522 signature;
# ConnectionRefusedError instead would mean 521.
start = time.monotonic()
try:
socket.create_connection(("203.0.113.10", 443), timeout=20)
print("handshake ok in", round(time.monotonic() - start, 2), "s")
except socket.timeout:
print("silent drop after", round(time.monotonic() - start, 2), "s -> 522")
except ConnectionRefusedError:
print("refused -> this is a 521, not a 522")
import requests
print(requests.get("https://www.example.com/", timeout=30).status_code)
Node (fetch)
// The edge answers with 522 well before your own client timeout fires.
const started = Date.now();
const res = await fetch("https://www.example.com/");
console.log(res.status, Date.now() - started, "ms");
// Classify it: timeout means 522, ECONNREFUSED means 521.
import net from "node:net";
const sock = net.connect({ host: "203.0.113.10", port: 443 });
sock.setTimeout(20_000);
sock.on("connect", () => { console.log("origin reachable"); sock.destroy(); });
sock.on("timeout", () => { console.log("SYN dropped -> 522"); sock.destroy(); });
sock.on("error", (e) => console.log(e.code));Reference and tooling
The authoritative list of assigned status codes is theIANA HTTP Status Code Registry. For a searchable copy with the semantics summarised, use theHTTP status code reference on this site. To see exactly what a server is sending, theheader inspector shows the raw status line and response headers, and thecurl builder assembles the request flags for you.
Other 5xx codes
- 500 Internal Server Error
- 501 Not Implemented
- 502 Bad Gateway
- 503 Service Unavailable
- 504 Gateway Timeout
- 505 HTTP Version Not Supported
- 506 Variant Also Negotiates
- 507 Insufficient Storage
- 508 Loop Detected
- 510 Not Extended
- 511 Network Authentication Required
- 520 Web Server Returns an Unknown Error
- 521 Web Server Is Down
- 523 Origin Is Unreachable
- 524 A Timeout Occurred
- 525 SSL Handshake Failed
- 526 Invalid SSL Certificate
- 530 Unable to Resolve Origin Hostname