Skip to main content

HTTP

502 Bad Gateway vs 504 Gateway Timeout

Short answer

A 502 means the attempt ended — refused, or the upstream died mid-response. A 504 means the attempt never ended, and the proxy stopped waiting. One is a failure; the other is a decision, and they need opposite fixes.

In simple terms

Both are a proxy telling you it could not give you the upstream's answer, which is why they get conflated. The difference is what happened to the attempt.

With a 502, something concluded badly. The connection was refused, or it opened and then closed without a complete response. There is an event you can point at.

With a 504, nothing concluded at all. The proxy gave up waiting, and — this is the part people miss — the upstream is quite possibly still working on it. Your request may well complete after you have been told it failed.

That distinction decides the fix. A 502 usually means finding what broke. A 504 means deciding whether the upstream is too slow or the timeout is too short, which are different problems with opposite remedies.

What actually happens

A 502 in nginx comes with a specific error-log line, and the lines map almost one-to-one onto causes: `connect() failed (111: Connection refused)` means nothing was listening; `upstream prematurely closed connection` means the socket opened and produced nothing; `upstream sent too big header` is a buffer limit; `no live upstreams` means the whole pool was ejected.

A 504 comes from a timeout expiring, and nginx names the stage: `while connecting to upstream` is the TCP handshake never completing, `while reading response header` is the upstream not answering in time. The default `proxy_read_timeout` is 60 seconds, which is why so many 504s arrive at suspiciously round intervals.

The stage matters more than the status. A connect-stage 504 is a network path problem — packets being silently dropped rather than refused, because a refusal would have produced a fast 502 instead. A read-stage 504 is about latency or queueing.

One consequence worth internalising: a 504 is not safe to retry blindly. The request may have been fully processed, so retrying a non-idempotent operation can duplicate it. A 502 from a refused connection is safe to retry; a 502 from a mid-response close is not, for the same reason.

Telling them apart from the proxy log alone

# 502 — the attempt concluded badly
connect() failed (111: Connection refused) while connecting to upstream
upstream prematurely closed connection while reading response header

# 504 — the attempt never concluded
upstream timed out (110: Connection timed out) while reading response header
upstream timed out (110: Connection timed out) while connecting to upstream
#                                                    └── network path, not latency

Both statuses look identical to the user and to most dashboards. The proxy's error log is where the distinction lives, and it is the most under-used artefact in this whole class of problem.

◑ The mistake this causes

Raising the proxy timeout because a 504 appeared.

Why people do it It works, immediately and visibly, which is exactly the problem. The 504 goes away and the underlying latency does not.

What you see The error rate drops and the p95 latency climbs. Users no longer see an error page; they wait thirty seconds instead. Worse, the timeout was the only thing reporting the regression, so raising it removed the signal along with the symptom — and the next investigation starts from a much weaker position.

How it shows up in production

The version that costs the most time is a 504 with nothing in the upstream's logs and a fast response when tested directly. Both facts seem to rule out the upstream, so the investigation goes to the network.

The usual cause is timeout ordering. Some inner hop has a longer timeout than the proxy, so the proxy gives up first while the chain is still working. The request completes eventually, logs a success, and nobody is listening by then — which is why the upstream logs look healthy and the client saw a failure.

The tell is comparing timestamps rather than reading either log alone: a request logged as completing successfully *after* the client's 504 is the whole diagnosis.

How to tell which one you are hitting

How quickly did the error arrive?
Immediately, or at a consistent round number of seconds? An instant failure is a 502 from a refusal. A consistent delay — often exactly 60 seconds — is a timeout expiring, so a 504.
What stage does the proxy log name?
`while connecting` points at the network path in both cases. `while reading response header` points at the upstream's behaviour. The stage narrows this faster than anything else.
Did the upstream log the request at all?
No log at all means it never arrived — reachability, so a 502. Logged and completed after the client gave up means a timeout ordering problem. Logged and still running means genuine slowness.
Is it safe to retry?
A refused connection, yes — nothing was processed. A 504 or a mid-response close, not blindly: the work may have completed, so a non-idempotent retry can duplicate it.
How this gets asked in an interview

Usually phrased as “What is the difference between a 502 and a 504?”

What a strong answer contains Frame it as concluded-badly versus never-concluded rather than reciting the status definitions, then give the consequence: a 502 means find what broke, a 504 means decide whether the upstream is too slow or the timeout is too short. Mentioning that a 504 is unsafe to retry blindly, because the work may have completed, is the point that shows operational experience.

The follow-up “You get a 504 and the upstream logs look fine — what now?” The answer they want involves timeout ordering across the chain, not raising the proxy timeout.

What comes next

Did this get you to an answer?

No text box on purpose — please do not paste production logs anywhere