504 Gateway Timeout
A 504 Gateway Timeout is an HTTP status code that means a proxy or gateway server did not receive a timely response from an upstream server it had to contact to complete the request. In plain terms, the edge of the chain — a reverse proxy, CDN, or load balancer — waited for the backend (the application, database, or API) and gave up before an answer arrived. The client then sees the gateway's timeout notice instead of the page or data it asked for.
What it means
Who reports a 504 matters as much as what it says: the error comes from the gateway, not from the server that failed. In a typical setup a client talks to a reverse proxy such as Nginx, Apache, HAProxy, or a cloud load balancer; that proxy forwards the request to one or more origin servers; the origin replies; the proxy returns the answer to the client. A 504 means the third step never finished in time. The origin may be overloaded, stuck on a slow database query, waiting on an external service, or simply down.
The five-hundred family of codes all point at trouble on the server side, but they differ in who reports them and why. 502 Bad Gateway means the upstream returned an invalid or unusable response. 503 Service Unavailable means the server is temporarily unable to handle the request, often deliberately, and it frequently carries a Retry-After header. 504 is specifically about waiting too long. That is why the useful logs for a 504 are the proxy's upstream-timing entries and the origin's slow-request log, not the client's browser console.
Timeouts are configurable values, so the same page can work one day and fail the next as load changes. A page that renders in 29 seconds behind a 30-second proxy limit is fine until the database slows down and the same page takes 31 seconds. The error is a boundary being crossed, not a fixed property of the page.
Common causes
- The backend application is slow or deadlocked — a long-running database query, a full table scan, or a lock held while another request waits.
- The origin server is overloaded or short of memory, CPU, or worker processes, so requests queue up and never get served.
- An upstream dependency such as a payment API, search service, or third-party endpoint is not answering, and the app blocks while waiting on it.
- Proxy or load-balancer timeout settings are too low for the work being done, or a failing health check removed the upstream from the pool.
- A network problem — dropped packets, a bad MTU, or a firewall silently discarding traffic — stops the response from ever returning.
How to fix it
- Find which server is timing out. Read the proxy log and the application log from the same instant. Look for the upstream address named in the error and the request path that was slow.
- Check that the backend is healthy. Confirm the app process is running and answering locally, for example
curl -I http://127.0.0.1:8080/. If that also hangs, the fault is in the application, not the proxy. - Raise the timeout only after you know why. In Nginx the relevant directives are
proxy_connect_timeout,proxy_send_timeout, andproxy_read_timeout:
A larger limit buys breathing room, but it does not fix a slow query, so do it alongside real optimisation.location / { proxy_pass http://127.0.0.1:8080; proxy_read_timeout 120s; } - Speed up the slow work. Add database indexes, cache expensive results, and move long jobs to a background queue so the request can return quickly instead of holding the connection open.
- Fix external dependencies. Give every outbound call its own short timeout and a small number of retries, and degrade gracefully when a third party is slow rather than blocking the whole request.
How to prevent it
Monitor response times, not just up/down status, and alert before the p95 latency reaches your proxy timeout. Put a caching layer in front of expensive endpoints, use a queue for anything that consistently takes more than a second or two, and make sure every outbound call carries its own timeout so one slow dependency cannot stall everything.
Keep proxy and application timeouts consistent with each other — a proxy that gives up sooner than the app can answer simply hides the real problem — and scale workers with load. Finally, test with realistic data and traffic. Slow paths usually only appear at real volume, and finding them in a rehearsal is far cheaper than finding them in production.