504 Gateway Timeout — how to fix it
Quick answer: 504 Gateway Timeout means your reverse proxy forwarded the request to your app but didn't get a response in time and gave up. Unlike a 502 (no/invalid response), the app is reachable but too slow. Find the slow endpoint, fix the slowness (a query, an external call, a blocked loop), and only raise proxy_read_timeout if the work is legitimately long.
What the error looks like
The proxy returns 504 and logs a timeout against the upstream:
# /var/log/nginx/error.log
upstream timed out (110: Connection timed out) while reading
response header from upstream, upstream: "http://127.0.0.1:3000/"
502 vs 504: a 502 means the upstream gave nothing or garbage; a 504 means it was reachable and simply too slow to answer within the timeout. The app is alive — it's the latency that's the problem.
Why it happens
A slow database query
An unindexed or heavy query holds the request open past the proxy timeout.
A slow external call
The endpoint waits on a third-party API that's slow or itself timing out.
A blocked event loop
Synchronous CPU-heavy work stalls the process so it can't respond in time.
Timeout set too low
The work is legitimately long but the proxy's read timeout is shorter than it needs.
Diagnose it in three steps
Find the slow endpoint
# Time the request straight at the app, bypassing the proxy
time curl -s http://127.0.0.1:3000/slow-endpoint > /dev/nullFind what it waits on
# Add timing/log lines around DB and external calls.
# Most 504s trace to one slow query or one slow dependency.Decide: fix or extend
# Accidentally slow -> fix the query/call.
# Legitimately long -> move it to a background job (return 202),
# or raise proxy_read_timeout for that route only.Make it fast, or make it async
Raising the timeout is the last resort, not the first. Most 504s are a slow query or a slow dependency you can fix. For genuinely long work, don't hold the HTTP connection open — accept the job, return immediately, and let the client poll:
# nginx: only extend the timeout where the work really is long
location /reports/generate {
proxy_pass http://app;
proxy_read_timeout 120s;
}
# Better: return 202 Accepted + a job id, do the work in a queue.
See the slow request, not just the timeout
Infraveil gives you request tracing and live logs across your services on your own servers, so a 504 isn't a guessing game — you can see which request is slow and what it's waiting on. Health checks catch a degraded instance, and recovery is approval-gated and recorded.
Frequently asked questions
What is a 504 Gateway Timeout?
A reverse proxy or gateway forwarded a request to the upstream app but didn't receive a response within its timeout, so it returned 504. The app is reachable but too slow.
What's the difference between 502 and 504?
502 means the upstream returned no valid response (crashed, not listening, wrong port). 504 means the upstream was reachable but took too long to respond.
How do I fix nginx 504?
Find and fix the slow endpoint (query, external call, blocked loop). For legitimately long work, move it to a background job, or raise proxy_read_timeout for that route only.
Should I just increase the timeout?
Only for genuinely long operations. For accidental slowness, raising the timeout hides the problem; for long jobs, prefer an async pattern (return 202 and let the client poll).