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.
Quick Cheat Sheet
| Aspect | 408 Request Timeout | 504 Gateway Timeout |
|---|---|---|
| Class | 4xx — Client Error | 5xx — Server Error |
| Who timed out? | Client (didn't finish sending) | Upstream server (didn't respond in time) |
| Issued by | Origin server | Reverse proxy / gateway / CDN |
| Client should retry? | Yes, often safe | Yes, with backoff |
What Each Code Means
408 Request Timeout (RFC 9110 § 15.5.9) is sent when the server was waiting for the client to finish sending the request and gave up. The client took too long to produce headers or upload a body. The server is essentially saying: "I'm closing this connection because you went silent."
504 Gateway Timeout (RFC 9110 § 15.6.5) is fundamentally different: it means the responding server is itself a proxy/gateway, and the upstream server it depends on didn't respond in time. The client did everything right; the failure is downstream of the proxy.
How They Show Up in Production
You will almost never see a real 408 in modern web apps — browsers don't typically stall mid-request, and most servers just close the connection silently. 408 is most often seen with slow file uploads or flaky mobile networks.
504 is everywhere in microservice architectures:
- Nginx returns 504 when an
upstreamblock exceedsproxy_read_timeout(default 60s) - AWS Application Load Balancer returns 504 when the target group doesn't respond within the idle timeout (default 60s)
- Cloudflare returns 504 when your origin takes longer than 100s (520-series for shorter failures)
- API Gateway returns 504 when the integration (Lambda, HTTP backend) exceeds the integration timeout (max 29s for REST APIs)
Debugging Each
- For 408: check client-side network logs, body size, and any
expect: 100-continueflow. On the server, look forclient_body_timeoutandclient_header_timeoutin Nginx. - For 504: the failure is upstream — check application logs of the origin, not the proxy. Common causes: a downstream DB query, a third-party API call, or a Lambda cold start exceeding the timeout.
A Subtle Rule
If you operate a reverse proxy and your own backend takes too long, return 504 (you are the gateway). Only return 408 from the actual origin server. Many devs incorrectly send 408 from a proxy.
Real-World Use Case
When AWS ALB times out waiting for an ECS task, it returns 504 to the browser. The fix is in the ECS task (slow DB query, missing index, blocking call), not in ALB config. Conversely, 408 from an Nginx static server during a large upload usually means tuning client_max_body_size and client_body_timeout.
Look Up Any Status Code
Related Comparisons
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.
HTTP 429 vs 503 — Too Many Requests vs Service Unavailable Comparison
http 429 vs 503: when to return Too Many Requests for per-client rate limits versus Service Unavailable for overall capacity issues. Includes Retry-After header guidance.
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.