Migrate to RunxBuild and earn up to $50 in hosting credit on your first deposit.

Calculate your savings
unxBuild
Back to Blog Troubleshooting

504 Gateway Time-out in Nginx: Your Upstream Was Too Slow, Not Nginx

Sean

Platform Writer

Jul 18, 2026
7 min read

A 504 Gateway Time-out from Nginx means Nginx, acting as a reverse proxy, waited for your backend application to respond and gave up before it did. The failure is not in Nginx - it is the upstream being too slow. The quick stopgap is to raise proxy_read_timeout so Nginx waits longer, but that only hides the symptom. The real fix is finding why the backend takes so long: a slow database query, an external API call with no timeout, or a request doing genuinely too much work. Treat the 504 as a pointer to a slow upstream, not a reason to keep increasing timeouts.

504 Gateway Time-out in Nginx: Your Upstream Was Too Slow, Not Nginx

It is worth separating 504 from its neighbours. A 502 is the backend gave a broken response; a 504 is the backend gave no response in time; a 503 is the backend is unavailable. A 504 specifically means slow, and that word is the whole diagnosis.

Table of contents

What the 504 actually means

Nginx as a reverse proxy sits in front of your application - a Python, Node, or PHP process, a database-backed API, whatever serves the request. When a request comes in, Nginx forwards it upstream and waits for a response. If the upstream does not respond within the configured timeout, Nginx returns 504 to the client.

So a 504 is a timeout between Nginx and your backend. The client sees Nginx’s error page, but the slowness is one hop further in. This is the key mental model: Nginx did its job and reported that the thing behind it was too slow.

That reframes the whole investigation. You are not debugging Nginx; you are debugging why your application took longer than the timeout to produce a response. The Nginx config controls how long it waits, but the reason it had to wait lives in your backend.

The quick stopgap: raise the timeouts

If a legitimately long operation is being cut off, increasing Nginx’s timeouts buys room:

location / {
    proxy_pass http://backend;
    proxy_connect_timeout 60s;
    proxy_send_timeout    60s;
    proxy_read_timeout    120s;   # the one that usually matters
}

proxy_read_timeout is the setting that governs how long Nginx waits for the backend to send a response, and it is the one behind most 504s. The default is 60 seconds; raising it to 120 or 300 gives a slow endpoint more time.

Reload after changing:

nginx -t && nginx -s reload

But be honest about what this does. It does not make anything faster - it makes Nginx more patient. If a request genuinely needs three minutes, raising the timeout is correct. If it needs three minutes because of a bug or a missing index, raising the timeout just delays the same 504 while users wait longer. Use it as a stopgap or for genuinely long operations, not as the fix for a slow query.

The real fix: find why the upstream is slow

The durable fix is making the backend respond in time. The usual suspects, roughly in order:

  • A slow database query. The most common cause by far - a missing index, a query that scans a whole table, a query that got slow as data grew. Check your slow query log.
  • An external API call with no timeout. Your backend calls a third-party service that hangs, and your request hangs with it. Every outbound call needs its own timeout.
  • A request doing too much. Generating a huge report, processing a large upload, or looping over thousands of rows synchronously in the request path.
  • Resource exhaustion. The backend is out of worker processes, CPU, or database connections, so requests queue and time out waiting for a free worker.

Look at your application logs and timing first. A 504 with a clear pattern - always the same endpoint, always when data is large - points straight at the slow operation. Fix that, and the 504 goes away without touching a timeout.

Move long work out of the request

When an operation is genuinely slow - a report, a video encode, a bulk import - the right answer is not a longer timeout. It is to stop doing that work inside the HTTP request at all.

The pattern is to hand the slow job to a background worker and return immediately:

  1. The request enqueues a job and returns a 202 with a job ID right away.
  2. A background worker processes the job off the request path.
  3. The client polls for status or gets notified when it is done.

This keeps every HTTP request fast - the thing that takes three minutes now runs in a worker, not in the connection Nginx is waiting on. No timeout can expire on a request that returns in milliseconds.

This is the architectural fix, and it is the correct one for any operation that is legitimately slow. Raising proxy_read_timeout to 300 seconds so a synchronous report can finish is a design that will keep generating 504s under load; moving the report to a worker removes the class of problem entirely. If you find yourself raising timeouts repeatedly, that is the signal to move the work off the request path.

FastCGI and check-the-basics

Two closing points.

If your backend is PHP-FPM rather than a proxied HTTP app, the timeout directive is different - it is fastcgi_read_timeout, not proxy_read_timeout:

location ~ \.php$ {
    fastcgi_pass unix:/run/php/php-fpm.sock;
    fastcgi_read_timeout 120s;
}

Setting proxy_read_timeout on a FastCGI location does nothing, which is a common source of but I raised the timeout and it still 504s. Match the directive to how the backend is connected.

And check the basics before deep debugging: is the backend actually running and reachable? A 504 can simply mean the upstream process crashed or is not listening. curl the backend directly, check its process is up, and read the Nginx error log (/var/log/nginx/error.log) - it names the upstream and the timeout, which tells you immediately whether you are looking at a slow backend or a dead one.

How this fits the rest of the stack

A 504 is really a story about where slow work belongs - in the request, or off it - which is one of the most consequential architecture decisions an app makes. A platform that makes background workers and health checks first-class is what lets you move slow jobs off the request path instead of nursing timeouts, so the 504 stops recurring. The RunxBuild hosting calculator lays out the service, database, storage, and bandwidth as separate line items, and the RunxBuild dashboard is where the team watches deploys, logs, and restarts as they happen.

Useful related references:

FAQ

What does a 504 Gateway Time-out mean in Nginx?

It means Nginx, acting as a reverse proxy, forwarded a request to your backend and did not get a response within the configured timeout, so it returned 504 to the client. The slowness is in the upstream application, not in Nginx - Nginx simply reported that the thing behind it was too slow.

How do I fix a 504 error in Nginx?

As a stopgap, raise proxy_read_timeout (or fastcgi_read_timeout for PHP-FPM) so Nginx waits longer, then reload with nginx -s reload. The real fix is finding why the backend is slow - usually a slow database query, an external call without a timeout, or a request doing too much work.

What is the difference between a 502 and a 504 in Nginx?

A 502 Bad Gateway means the backend returned an invalid or broken response. A 504 Gateway Time-out means the backend returned no response within the timeout. A 502 is the upstream is broken; a 504 is the upstream is too slow, and that word points at the diagnosis.

Which Nginx timeout controls the 504?

For a proxied HTTP backend it is proxy_read_timeout, which governs how long Nginx waits for the backend to send a response - the default is 60 seconds. For a PHP-FPM backend it is fastcgi_read_timeout instead. Setting the wrong one has no effect, a common source of persistent 504s.

Should I just increase the Nginx timeout to fix a 504?

Only as a stopgap or for genuinely long operations. Raising the timeout makes Nginx more patient, not the backend faster, so if the slowness is a bug or a missing index it just delays the same 504. For legitimately slow work, move it to a background worker so the request returns quickly.

#504 gateway time-out nginx#nginx#504#reverse proxy#dev-infra