All three of these errors come from a machine sitting in front of your website, not from your website. That single fact does most of the diagnostic work. The error page you’re staring at was written by something that couldn’t reach your application (a load balancer, a CDN edge, a reverse proxy), and each code tells you a different thing about how the conversation failed.
The One-Line Version
| Code | What the front-end machine is saying | Your app |
|---|---|---|
| 502 Bad Gateway | “I reached your app and got back garbage.” | Answered, badly |
| 503 Service Unavailable | “I’m refusing this request on purpose.” | Usually never contacted |
| 504 Gateway Timeout | “I asked your app and waited. Nothing came back.” | Alive but too slow, or hung |
Those distinctions come straight from the specifications. MDN’s definition of 502 is a gateway receiving an invalid response from the upstream server; 504 is the same situation except no HTTP response arrived at all within the timeout. The line between them is whether your server said something wrong or said nothing.
503 Is the Odd One Out
Most people frame this as 502 vs 503 vs 504, three siblings on a list. A more useful grouping puts 502 and 504 together and leaves 503 on its own.
A 502 or a 504 means something tried to talk to your application and the attempt went wrong. A 503 usually means nothing tried at all. MDN describes 503 as the server not being ready to handle the request, with maintenance and overload as the common causes — and in the overload case, some applications deliberately reject requests with a 503 once memory, CPU, or connection-pool limits are hit. That rejection is a feature. Shedding load creates backpressure that stops the machine falling over entirely.
So a 503 can mean your deploy is running normally, or it can mean your site is drowning. The code alone won’t tell you which, which is exactly why it deserves different handling from the other two.
Reading the Codes as Evidence
Treat each one as a statement about where in the chain the failure sits.
- 502 points at your application returning something malformed, or dying mid-response. A process that crashed while writing output, a backend listening on the wrong port, a PHP-FPM pool that ran out of workers. The proxy is healthy; whatever it proxies to is not.
- 504 points at slowness rather than breakage. A query without an index, an external API call with no timeout of its own, a job doing real work inside a web request. Your app may well complete the work eventually, long after the proxy gave up.
- 503 points at capacity or intent. Maintenance mode, an autoscaler with nothing to scale to, a rate limiter — though a well-behaved rate limiter should return 429, not 503.
One caveat worth holding onto: none of these prove the origin is the culprit. If a CDN or reverse proxy is itself unhealthy, it can emit a 502 while your servers sit idle and perfectly fine. Check whether the error appears from more than one network before you go rebuilding an application that was never broken. That’s the same reasoning behind multi-region validation for false-positive downtime alerts: one vantage point isn’t evidence.
What Monitoring Should Do With Them
Most explainers stop at the definitions. The practical question is which of these should wake somebody up.
FlareWarden’s answer is deliberately blunt. Any response from 200 through 399 counts as up. A narrow set of refusal codes (401, 403, 407, 418, 429, 451) counts as the origin being alive but declining to talk to a robot, so they never open an incident. Everything else, and that includes all three of 502, 503, and 504, counts as down and gets treated like an outage.
That means a scheduled maintenance window served as 503 will page you. We think that’s the right default, because the alternative is worse: a monitor that ignores 503 will also ignore the 503 your overloaded application starts emitting at 9 a.m. on launch day, which is a real outage wearing a maintenance costume. The fix isn’t to soften the rule, it’s to declare the maintenance — scheduled maintenance done right keeps the window out of your uptime figures without teaching your monitoring to shrug at a genuine failure.
The Diagnosis Order That Saves Time
Work outside-in, because the outer layers are faster to rule out.
- Check from a second network. Phone on mobile data, or a tool like our free site checker. An error only you can see is a local DNS or proxy problem, not an outage.
- Check your platform’s status page. If your host, CDN, or PaaS is having an incident, everything below is wasted effort.
- Ask whether your app was reached at all. Look for the request in your application logs. Present means 502 or 504 territory: your code ran and misbehaved or stalled. Absent means the request died in front of your app, which points at 503, a misconfigured upstream, or a process that isn’t listening.
- For 504 specifically, find what’s slow. The timeout value tells you the budget you blew. A 504 after exactly 30 or 60 seconds is almost always a proxy default, not a coincidence.
- For 503, ask whether it was deliberate. Did someone deploy? Is maintenance mode on? If not, you’re looking at capacity.
The Part Worth Fixing Permanently
A 504 is the one that should bother you most, and not because it’s the most severe. It’s the one that was preceded by a warning you could have caught.
Applications rarely jump from healthy to timing out. They get slower first — a response time that drifts from 300ms to 1.2 seconds over a fortnight, still returning 200 the whole way, still invisible to any check that only asks “did it respond?” By the time a proxy starts returning 504, the degradation has been visible in your own response-time data for days. That gap between “slow” and “down” is where the useful warning lives, and it’s the subject of why a website can be slow but not down.
Key Takeaways
- All three come from in front of your app — a proxy, load balancer, or CDN generated the page, so the error describes a failed conversation, not your application’s own opinion.
- 502 means garbage, 504 means silence — the difference between the two is whether your server sent a malformed response or no response at all before the timeout.
- 503 belongs in its own category — it’s usually a deliberate refusal for maintenance or load shedding, which is why the code alone can’t tell you whether anything is wrong.
- Treat all three as down, then declare maintenance properly — a monitor taught to ignore 503 will also ignore the 503 an overloaded app emits during a real incident.
- 504s announce themselves in advance — sustained response-time drift precedes gateway timeouts by days, and only a check watching latency will show it.
Want to know which error your visitors are getting, and from where, before you do? Start monitoring free with FlareWarden — multi-region verification on every plan, 15 monitors, no credit card required.