HTTP 502 vs 504 — Bad Gateway vs Gateway Timeout Comparison
http 502 vs 504: both come from your reverse proxy, but 502 means the upstream returned a bad response while 504 means it didn't respond in time. Nginx, ALB, Cloudflare debugging tips.
Quick Cheat Sheet
| Aspect | 502 Bad Gateway | 504 Gateway Timeout |
|---|---|---|
| Upstream responded? | Yes, but invalidly (or connection failed) | No — exceeded timeout |
| Cause | Backend crash, malformed response, conn reset | Slow query, blocked thread, hung process |
| Fix priority | Restart / fix backend | Tune timeouts AND fix slow path |
| Common Nginx config | proxy_pass upstream issues |
proxy_read_timeout exceeded |
The Distinguishing Factor: Did the Upstream Respond?
Both 502 and 504 come from a proxy/gateway, not from your application directly. The difference is what the upstream did:
- 502 Bad Gateway: the upstream returned something, but the proxy couldn't make sense of it (malformed HTTP, unexpected EOF, connection reset, or refused connection).
- 504 Gateway Timeout: the upstream simply didn't respond within the configured timeout. Maybe it's slow, maybe it's hung, maybe it's gone.
Real-World Triggers
For 502:
- Backend process crashed mid-request (segfault, panic, OOM)
- Backend closed the connection without sending a response (e.g.,
process.exit()in middle of handler) - Upstream sent invalid HTTP headers (rare, usually a buggy custom server)
- TLS handshake failure between proxy and backend
For 504:
- A slow database query holds up the request (
SELECTwithout an index) - The backend is waiting on a third-party API that's slow
- Lambda cold start exceeds API Gateway integration timeout (29s for REST APIs)
- Thread pool exhausted, request queued behind others
- Backend is in a deadlock or infinite loop
Timeouts in Common Stacks
| Layer | Default Read Timeout |
|---|---|
Nginx proxy_read_timeout |
60s |
| AWS ALB idle timeout | 60s (configurable up to 4000s) |
| AWS API Gateway REST integration | 29s (hard cap) |
| Cloudflare Free | 100s |
| Vercel serverless | 10s (Hobby), 60s (Pro), 900s (Enterprise) |
If your backend ever takes longer than these, the user gets 504 even if the work completes successfully on the backend.
Debugging Workflow
For 502:
- Check the upstream process — is it running? Crash logs?
curl localhost:PORT/pathdirectly from the proxy host — what comes back?- Look at proxy error logs, not access logs (Nginx:
/var/log/nginx/error.log) - Check for
upstream prematurely closed connectionerrors
For 504:
- Check application logs for the request — does it appear and complete? In how long?
- If the backend log shows the request finishing in 75s but the proxy timeout is 60s, the fix is either to speed up the backend or raise the timeout
- If the backend has no record of the request, it's probably 502 territory after all
- Check database slow-query logs
Don't Just Raise Timeouts
A common but bad fix for recurring 504s is to crank up proxy_read_timeout to 600s. This often masks the real problem (a slow query) and creates new issues (connections held open, thread pool exhaustion). Profile and fix the slow path instead.
Cloudflare's Variants
Cloudflare uses 520-526 for various edge-to-origin problems:
- 520: empty response
- 521: web server is down
- 522: connection timed out
- 523: origin unreachable
- 524: a timeout occurred (the closest analog to 504)
Real-World Use Case
A Cloudflare-fronted API showing 504 for one specific endpoint usually means a slow DB query — first profile the query plan, add an index, and only then consider raising Cloudflare's timeout. A 502 from AWS ALB right after deploying a new version often means the new container is crashing on startup; check ECS task health and logs.
Look Up Any Status Code
Related Comparisons
HTTP 500 vs 502 — Internal Server Error vs Bad Gateway Comparison
http 500 vs 502: 500 is your application crashing, 502 is your reverse proxy unable to reach the upstream. Learn the debugging workflow for each.
HTTP 502 vs 503 — Bad Gateway vs Service Unavailable Comparison
http 502 vs 503: 502 is an *unintentional* upstream failure detected by a proxy, 503 is an *intentional* unavailability signal from the application. Why this distinction matters for incident triage.
HTTP 503 vs 500 — Service Unavailable vs Internal Server Error Comparison
http 503 vs 500: 503 is intentional (overload, maintenance) and includes Retry-After, while 500 is an unintentional crash. Why the right choice affects monitoring and SLAs.
HTTP 408 vs 504 — Request Timeout vs Gateway Timeout Comparison
http 408 vs 504: who timed out, the client or an upstream server? Learn the difference, when each is returned, and how to debug timeouts in Nginx, ALB, and Cloudflare.