ProductionIntermediate

502 vs 503 vs 504

“Your service sits behind a load balancer. Users report 502, 503 and 504 errors. What does each one mean, who generated it, and where do you look first for each?”

What this tests

  • The semantic difference: bad response, no capacity, no response in time
  • That the proxy — not the application — is usually the author
  • Mapping each code to a concrete failure in the upstream connection
  • That exact mappings differ between nginx, Envoy, ALB and CDNs

Answers by level

Read the beginner answer first and notice what is missing.

All three are almost always written by the proxy in front of your service — the L7 balancer, ingress or CDN (Forward and Reverse Proxies, Load Balancers: L4 vs L7) — which is why the application logs often show nothing. They describe what happened on the proxy’s upstream connection. 502 Bad Gateway: the proxy connected (or tried to) and got something it cannot use — connection refused because no process is listening (crashed, restarting, wrong port), a reset because the backend closed an idle keep-alive connection the proxy was about to reuse (Keep-Alive and Connection Reuse), a TLS failure toward the upstream, or a malformed or oversized response header. First look: is the process up, did a deploy just happen, and do the proxy’s error logs say connect() failed, upstream prematurely closed, or upstream sent too big header.

503 Service Unavailable: there is nothing to send to, or the backend refused to serve. From the proxy: no healthy backends — every target failed health checks, the target group is empty, all pods are not-ready during a rollout, the deployment scaled to zero. From the application itself: deliberate load shedding, a maintenance mode, an open circuit breaker, or a queue full — the one code of the three that a backend *should* emit on purpose, ideally with Retry-After. First look: the health-check dashboard and readiness state, then whether the 503 body or Server header is the proxy’s or yours.

504 Gateway Timeout: the proxy sent the request and the backend did not answer within the proxy’s timeout — nginx proxy_read_timeout (60 s default), ALB idle timeout (60 s), Envoy route timeout (15 s). The backend is alive and probably still working on that request: a slow query, a lock, a downstream call without its own timeout, a thread pool exhausted so the request sat in a queue. First look: backend latency percentiles and saturation, not errors. The ugly part: the client got an error but the work may complete anyway, so a retry can double-charge; deadlines must propagate so the backend stops when the proxy gives up.

The mappings are not standard across proxies, and you must know your own. nginx returns 502 for connection refused and 504 for a *connect* timeout; Envoy returns 503 for upstream connect failure (UF), no healthy hosts (UH) and overflow (UO) and 504 only for UT; AWS ALB returns 502 for reset/refused/malformed and 503 for a target group with no registered targets; Cloudflare uses its own 52x family — 521 origin refused, 522 connect timeout, 524 response timeout after 100 s, 525/526 TLS problems — so a "504" from an origin behind Cloudflare arrives at the user as 524. Reading the code without knowing which hop wrote it is guessing. See HTTP Debugging: 502, 503 and 504 Are Different Failures.

Green flags · Red flags

Strong green flag · Describes the deploy sequence 502 → 503 → 504 and the readiness/drain fixes, or recognises the keep-alive-race 502 pattern.
Green flags
  • Says the proxy usually generates these and explains what it observed on the upstream side
  • Maps 502 → refused/reset/malformed, 503 → no healthy backend or deliberate shedding, 504 → upstream too slow
  • Names the first place to look for each
  • Points out that nginx, Envoy, ALB and CDNs map failures to codes differently
  • Notes that a 504 request may still complete and that retries need idempotency
Red flags
  • Sends the application team to look for exceptions for all three
  • Cannot tell 502 from 504
  • Thinks 503 always means overload
  • Treats the codes as a universal standard across proxies

Follow-up questions

F1
ALB logs show elb_status_code=502 and target_status_code=-. What does the dash tell you?
F2
Envoy returns 503 with flag UF. What is the nginx equivalent?
F3
A 504 on a payment POST: safe to retry?

Scenario

During every rolling deploy, a dashboard shows a 30-second burst of 502s followed by a shorter burst of 503s, and the application logs are clean. Reconstruct the sequence of events at the load balancer and list the configuration changes that remove each burst.

Learn this topic