502 Bad Gateway is not your server saying no

30/07/2026 · Laurent HTTP status codes
502 Bad Gateway is not your server saying no

Every guide about this error opens with a list. Clear your browser cache, restart your router, disable your plugins, contact your host. If you run one website, one of those might eventually work by accident. If you run forty, that list is worse than useless, because it sends you looking in the one place the error has already told you not to look.

A 502 has a narrow meaning. Something in front of your site asked your site for a page, and what came back was either nothing or something it could not parse as HTTP. The machine that wrote you the error is not the machine that failed. That is the whole content of the code, and almost everything useful follows from it.

Who is talking to you

The 502 page in your browser was written by a proxy. Depending on your stack that is nginx sitting in front of PHP-FPM, a load balancer in front of a pool of application servers, Cloudflare in front of your origin, or a shared host's frontend in front of the container your client's site lives in. Often several of them are stacked, and only the outermost one gets to write the page you see.

That machine is up. It accepted your TCP connection, it completed the TLS handshake if there was one, it parsed your request, it decided where to send it, and it generated an error page. None of that is possible for a host that is down. So the first thing a 502 buys you is an elimination: DNS resolved, the network path works, the front door answers. Whatever is broken is behind that door.

This is also why clearing your browser cache does nothing. Your browser was never the problem, and a 502 is not usually cached anyway.

What actually produces one

Upstream failures fall into four shapes, and telling them apart is most of the work.

ShapeWhat the proxy sawTypical cause
RefusedConnection refused on the upstream portThe application process is not running. PHP-FPM stopped, the Node process crashed, the container exited.
ResetConnection opened, then dropped mid-responseThe worker died while handling the request. Out of memory is the usual reason.
GarbageBytes arrived, but not a valid HTTP responseSomething printed before the headers. A warning, a BOM, a stray var_dump in a file that got deployed.
ExhaustedNo free upstream to hand the request toEvery worker is busy. The site is not broken, it is full.

The last one is the reason 502s are so often intermittent, and the reason they are so often reported by a client and not reproducible by you. When the pool is saturated, requests fail in proportion to how full it is. At eighty percent you get a handful of errors an hour, scattered, on no particular page.

Three commands that settle it

Run these from a machine that is not your laptop if you can, so that your own network is out of the picture.

First, confirm the code is real and see who wrote it:

curl -sSI https://example.com/

Read the Server header and any Via or CF-Ray lines. They name the proxy. If you see a Cloudflare identifier, your origin may be perfectly healthy and unreachable from Cloudflare's edge, which is a different problem with a different fix.

Second, ask the origin directly, bypassing whatever sits in front:

curl -sSI --resolve example.com:443:203.0.113.10 https://example.com/

Substitute your origin's address. If this returns 200 and the public URL returns 502, the failure is between the edge and your server, not inside your server. That distinction saves an hour and a support ticket sent to the wrong company.

Third, check whether it is the whole site or one path:

for p in / /wp-login.php /robots.txt; do
  printf '%s ' "$p"; curl -s -o /dev/null -w '%{http_code}\n' "https://example.com$p"
done

A static file answering 200 while every dynamic page answers 502 is the signature of a dead application process with a live web server. That is the most common shape on shared hosting, and it usually means a restart, not a debugging session.

The part that concerns anyone watching sites for other people

An intermittent 502 is harder to catch than a site that is flat on its back, and most monitoring is built for the second case. A checker that polls every five minutes sees three hundred requests a day. If one request in fifty is failing, that checker has a good chance of reporting a perfect day while your client's customers are hitting errors at checkout.

Two things help, and neither is exotic. Confirm failures rather than alerting on the first one, so a single unlucky request does not wake you, but count the unconfirmed ones, because that count is the signal. A monitor that only records confirmed outages throws away exactly the data that would have shown you a pool filling up over three weeks.

The other thing is to stop treating 502 as a special case in your alerting. Teams often exclude it because it is noisy. Excluding your noisiest failure mode because it is noisy is how a slow degradation becomes an outage on a Friday afternoon.

When it is not a 502 at all

Two codes get mistaken for this one often enough to be worth naming. A 504 means the proxy waited and gave up, so the upstream is alive but slow, and the number you need to look at is a timeout setting rather than a process list. A 503 usually means something deliberately refused to serve, which includes maintenance mode and rate limiting, and it is the only error in this family you might have caused on purpose.

And there is the case that looks worst on paper and is easiest to fix: a page that returns 200 with a fatal error printed inside it. No proxy will flag that, no status code will tell you, and every uptime checker built on status codes alone will report the site as fine. If you want to see what that looks like on a real address, the free checker here reads the body as well as the code, and it will tell you when the two disagree. The longer version of what a status code cannot see is in the guide to what these tools actually check.

If you are chasing one right now: get the origin's own answer with the second command above. Everything else in this article is downstream of knowing whether your server is the one saying no.

Share this post.
Stay up-to-date

Subscribe to our newsletter

Don't miss this

You might also like