WatchFor
ReferenceHTTP Status Codes

504 Gateway Timeout

What HTTP 504 means, how timeout chains between CDN, load balancer and app interact, and how to hunt the slow dependency behind it.

504 Gateway Timeout comes from a proxy that connected to the upstream server just fine — and then waited, and waited, and hit its timeout before a response arrived. Where a 502 means "upstream answered badly", a 504 means "upstream didn't answer in time". The request may even still be running when the user sees the error.

Common causes

  • A slow query — the request handler is stuck on a database query that takes longer than the proxy's timeout; the classic 504 origin story
  • Slow third-party calls — the handler synchronously awaits an external API with no timeout of its own
  • Timeout chain misalignment — CDN times out at 30s, LB at 60s, app at 120s: users get 504s from the CDN while the app happily keeps computing work nobody will receive. Timeouts should decrease toward the edge… or rather, each outer layer should allow slightly more than the inner one needs to respond.
  • N+1 and unbounded work — endpoints whose duration grows with data size until one customer's dataset crosses the timeout
  • Lock contention — requests serialised behind a table lock or a distributed mutex
  • Undersized capacity — requests spending most of their time queued before processing even starts

Debugging

  1. Find how long the upstream actually takes. Server-side latency histograms or slow-query logs tell you whether the work is legitimately slow or stuck.
  2. Map the timeout chain. Write down every layer's timeout (CDN, LB, reverse proxy, app server, database driver) — the 504 comes from the first one to give up.
  3. Fix the work, not the timeout. Raising limits converts a fast failure into a slow one. Cache, index, paginate, or move the work to a background job with an async status endpoint.

504s rarely appear out of nowhere — latency creeps up for days first. An HTTP monitor tracks response times from multiple regions continuously, so you see the climb and can alert on a response-time threshold before the timeout line is crossed.

On this page