# 504 error: what gateway timeout means and how to fix it

> A 504 error means a proxy in front of the website waited for the server behind it to answer and gave up. Visitor fixes first, then how owners find the request that times out and fix it without blindly raising timeouts.

Updated 2026-10-16 · Technical SEO · HTML version: https://getreport.app/guides/504-gateway-timeout

A 504 error (the full name is 504 gateway timeout) means a server in the middle asked the real web server for the page and gave up waiting for the answer. The server behind it did not crash or refuse; it was still working when the clock ran out. Nothing on the visitor's device is wrong, and the fix is always on the site's side: find the request that is too slow, and make it faster. This guide shows visitors the one-minute version, then walks owners through the chain of timeouts, the log fields that name the slow request, and the honest order of fixes. For where 504 sits among all the codes, see the [guide to HTTP status codes](https://getreport.app/guides/http-status-codes).

## Quick answer

- **Visitor:** reload once, come back in a few minutes. You cannot cause or fix a 504; the work may even have finished after the error appeared.
- **A 504 is a race between clocks.** The browser waits for the proxy, the proxy waits for the app, the app waits for a database or API, and the shortest patience in the chain decides who gives up first.
- **Owner: find the slow request first.** Log `$request_time` and `$upstream_response_time` in nginx, switch on the database's slow query log, and the 504s almost always cluster on a few endpoints: exports, reports, search.
- **The common limits:** nginx `proxy_read_timeout` and `fastcgi_read_timeout` default to 60 seconds; PHP's `max_execution_time` to 30; Cloudflare waits 125 seconds, then shows its own error 524.
- **Fix the work, not the clock.** Make the slow request faster or move it to a background job before you raise any timeout.
- **504 vs 502:** a 504 means no answer in time; a [502](https://getreport.app/guides/502-bad-gateway) means a broken answer right away. Different causes, different fixes.

## What does a 504 error mean?

The HTTP standard (RFC 9110) defines 504 gateway timeout as a gateway or proxy that did not receive a timely response from the server it contacted on your behalf. "Gateway" is the middleman most sites have in front: nginx passing requests to PHP-FPM or an app process, a load balancer, or a CDN such as Cloudflare.

What makes a 504 different from every other 5xx is that nothing is broken at the moment it is sent. The application accepted the request and is still working on it. The proxy simply has a rule ("if no answer after N seconds, stop waiting") and that rule fired. One request is really a chain of waits: the browser waits for the proxy, the proxy waits for the application, the application waits for a database query or a third-party API. Each link has its own patience, and the link with the shortest patience decides which error appears and where.

![Timeline of a 504 gateway timeout: a request enters at 0 seconds, the application is still working at 60 seconds when the proxy's timeout ends and it returns 504, and the application finishes at 90 seconds with no one left to receive the answer](https://getreport.app/guides/img/504-gateway-timeout/diagram.svg "The proxy's patience ends at 60 s and the visitor gets a 504; while the app keeps working to 90 s for nobody.")

That picture is the whole problem in one line: the server finishes the work at 90 seconds, but the proxy stopped listening at 60. The visitor got an error, the server paid the full cost anyway, and if the request wrote something (an order, an import) it may even have succeeded after the error page was shown.

## If you're a visitor: the quick fix

A 504 happens between the website's own servers, after your request arrived intact. The honest list is short:

1. **Reload once.** Many 504s are one overloaded moment or one uncached page; the second try often hits a faster path.
2. **Come back in a few minutes.** If the site is overloaded, piling on retries keeps it overloaded.
3. **Don't resubmit a payment, order or upload.** The server may have finished the work after the error appeared. Check your email or account for a confirmation first.
4. **Tell the site owner** if it keeps happening, with the time and the exact page: especially if it is always the same page. That detail does half their diagnosis for them.

Nothing on your side (cache, cookies, DNS, router) causes a 504, so there is nothing more useful to clear or restart.

## Is it a 504 or a 502?

The same proxy produces both codes, one failure apart. A [502 bad gateway](https://getreport.app/guides/502-bad-gateway) means the proxy got an answer and it was broken: the connection refused or reset, the response invalid. A 504 means the proxy got no answer at all before its patience ran out. Broken now versus silent too long.

The distinction matters because the fixes don't overlap: a 502 sends you to a crashed or misconfigured upstream (the 502 guide covers the log lines and restarts), while a 504 sends you hunting for slowness. If your error page says 502, switch guides; raising timeouts will do nothing there. If the codes alternate under load, you usually have a capacity problem wearing both masks: some requests queue until they time out, others hit a process the kernel just killed.

## If you own the site: find the request that times out

Resist the urge to open the timeout settings first. A 504 names a symptom (too slow) and the only durable fix starts with knowing *which* request is slow and *where* its time goes.

### Make the access log tell you the time

nginx's default log format does not include timings, but two variables from its documentation give you everything: `$request_time` (total time nginx spent on the request) and `$upstream_response_time` (how long the app behind it took). Add a format and use it:

```nginx
# /etc/nginx/nginx.conf: inside the http block
log_format timed '$remote_addr [$time_local] "$request" $status '
                 'rt=$request_time urt=$upstream_response_time';

# in your server block
access_log /var/log/nginx/access.log timed;
```

Reload nginx, wait for traffic, then look at the slowest lines: `sort` by the `rt=` field or just grep for ` 504 `. A matching line in `/var/log/nginx/error.log` reads `upstream timed out (110: Connection timed out) while reading response header from upstream`; that exact text is nginx saying its read timeout fired.

### Follow the time downwards

In almost every real 504 the application is itself waiting on something slower. Switch on the database's slow query log (in MySQL, `slow_query_log = 1` with `long_query_time` lowered from its default of 10 seconds to 1 or 2) and the query behind the slow endpoint usually introduces itself within the hour. If the app calls third-party APIs, log those durations too; a payment or shipping API having a bad day produces 504s on your checkout that no server graph explains.

Then look at *which* URLs time out. It is rarely the whole site. The classic pattern is a handful of endpoints that do unbounded work in one request: a CSV export that grows with the customer's data, a report that aggregates a year of rows, a search with no index behind it, an admin import. Each worked fine when the data was small; the data grew and the request walked past 60 seconds.

## The timeouts, their defaults, and where they live

Every hop has a clock. These are the ones that produce most 504s, with their defaults:

| Clock | Default | Where it lives |
| --- | --- | --- |
| nginx `proxy_read_timeout` (proxied apps) | 60 s | the `location` or `server` block in `/etc/nginx/sites-available/…` |
| nginx `fastcgi_read_timeout` (PHP-FPM) | 60 s | the `location ~ \.php$` block, same files |
| PHP `max_execution_time` | 30 s | `php.ini`; `request_terminate_timeout` in the FPM pool can cut in too |
| Cloudflare proxied requests | 125 s, fixed | Cloudflare's edge; only Enterprise plans can raise it (up to 6,000 s) |

The shortest clock wins, and *who* times out decides what the visitor sees. If PHP's 30 seconds fire first, the script is killed and you typically get a 500, not a 504. If nginx's 60 seconds fire first, nginx answers 504 while PHP works on. And with Cloudflare in front, your own 504 at 60 seconds passes through as a 504, but if your whole stack would happily wait longer than 125 seconds, Cloudflare's documentation says it cuts in with its own error 524, "a timeout occurred", at 125 seconds. A 524 on a proxied site *is* a gateway timeout; it just wears Cloudflare's number.

## The honest fix order

Raising a timeout does not make anything faster. It makes everyone (the visitor, a browser tab, a held connection, a busy PHP worker) wait longer for the same slow work, and busy workers held for minutes are how one slow endpoint takes down the fast pages around it. So the order is:

1. **Make the slow work faster.** For a slow query: an index, a smaller date range, pagination. For a slow page: caching, so only the first visitor pays. This fixes the 504 and the [slow time to first byte](https://getreport.app/guides/ttfb-what-a-slow-server-looks-like) that was creeping up before it.
2. **Make long work asynchronous.** Anything that legitimately needs minutes (exports, imports, report generation) should not live inside one HTTP request at all. Accept the job, answer immediately, do the work in a background queue, and let the user poll or get an email with the download link. The request that answers "working on it" takes 200 ms and can never 504.
3. **Only then, raise the timeout: narrowly.** Raising is legitimate when a request is genuinely long, rarely used, and not worth a queue yet: one admin report, one webhook receiver doing a slow sync. Raise it on that one `location` block, not server-wide, and remember every hop must agree; nginx at 300 s achieves nothing while PHP still kills the script at 30, or Cloudflare at 125:

```nginx
# /etc/nginx/sites-available/example.com: only the one slow endpoint
location /admin/export {
    fastcgi_read_timeout 300s;   # proxy_read_timeout for a proxied app
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
```

A server-wide 300-second timeout is the classic non-fix: the 504s disappear from the logs, the users now stare at a spinner for five minutes, and the next data growth brings the errors back anyway.

## Watch your server's patience from outside

A server rarely jumps from fast to timing out overnight; it drifts there. Time to first byte is the early warning: it is the same wait the proxy's clock measures, seen from outside.

> **Free tool:** [TTFB test: check your time to first byte](https://getreport.app/tools/ttfb-test): Free TTFB test: measure time to first byte from Frankfurt, in a Lighthouse run and from real Chrome users, plus the redirects before the page. No sign-up.

The TTFB test requests your page from Frankfurt and shows the first-byte time next to Lighthouse's and the one from real Chrome users. A page whose TTFB keeps climbing toward seconds is a 504 in the making: the same growth that took it from 200 ms to 4 s will take it past 60. In a full report, two findings watch this for you:

> **Check: Time to First Byte.** TTFB is how long the server takes to start answering. Everything else waits for it, so a slow first byte makes every other metric worse. Google's 800 ms target is for real visitors, network included; Lighthouse flags the server's own share above 600 ms (see server response time).
>
> 1. Add page caching (WordPress: WP Rocket, LiteSpeed Cache, or your host's cache; Shopify does this for you).
> 2. Put a CDN in front (Cloudflare, Bunny) so the first byte comes from a nearby edge.
> 3. Check database-heavy plugins and slow hosting; a plan with more CPU often fixes this outright.

> **Check: Server response time.** Lighthouse flags a first byte slower than 600 ms. Caching and hosting fix this for most CMS sites.
>
> 1. Enable full-page caching (WordPress: WP Rocket, LiteSpeed Cache, WP Super Cache; or your host's server cache).
> 2. Use a CDN and keep database queries out of the request path.

Run the test on your handful of known-heavy pages (search, category filters, account dashboards) not just the home page, because that is where the drift starts.

## Does a 504 hurt SEO?

Google Search Central's documentation on HTTP status codes says Googlebot treats all 5xx errors alike (crawl rate drops while they last, and URLs that persistently fail are dropped from the index) so a brief 504 costs nothing and a chronic one does. The [502 guide's SEO section](https://getreport.app/guides/502-bad-gateway) covers the details, and they apply to 504s unchanged. One trap is specific to timeouts, though: slow pages that *almost* time out waste crawl budget long before they fail, so fixing the slowness pays twice.

## Questions people ask

### What does a 504 error mean?

It means a proxy in front of the website (nginx, a load balancer or a CDN) asked the real server for the page and gave up waiting before an answer came. The server behind it was still working, just slower than the proxy's timeout, which is 60 seconds by default in nginx. It is a server-side problem: visitors cannot cause it and cannot fix it.

### How do I fix a 504 gateway timeout?

Find the slow request first, then speed it up. Log timings in the access log (`$request_time`, `$upstream_response_time`), switch on the database's slow query log, and the 504s will cluster on a few heavy endpoints: exports, reports, search. Fix those with an index, caching or a background queue. Raise a timeout only for a genuinely long, rarely used request, on that one endpoint, matching the limit on every hop in the chain.

### What is the difference between 502 and 504?

A 502 means the proxy got an answer and it was broken: the connection was refused or reset, or the response was invalid; the server behind it is down or crashing. A 504 means the proxy got no answer at all before its timeout ran out; the server is alive but too slow. That is why restarts fix most 502s and never fix 504s, and raising timeouts can mask a 504 and never helps a 502.

### Why do I get 504 errors only on some pages?

Because the timeout is per request, and only some requests do enough work to exceed it. Pages that aggregate or search large data (exports, reports, unfiltered product searches, admin imports) grow slower as the data grows, while cached and simple pages stay fast. That pattern is good news for the diagnosis: the slow query or loop behind those specific URLs is the cause, and fixing or queueing it ends the 504s.

### Can Cloudflare cause 504 errors?

Cloudflare's own timeout does not show as a 504: if your origin takes longer than 125 seconds, Cloudflare returns its error 524 instead, and only Enterprise plans can raise that limit. A real 504 on a Cloudflare-proxied site was almost always generated by your own stack (typically your nginx giving up on your app at 60 seconds) and passed through, so the diagnosis belongs on your server, not in the Cloudflare dashboard.

### Does raising the timeout fix a 504 error?

Only in the narrow case where the request is legitimately long, rarely used, and every hop's limit is raised together: one admin export behind its own `location` block, for example. Everywhere else it trades an error page for a minutes-long spinner, holds server workers hostage while they wait, and returns as soon as the data grows again. Make the work faster or move it to a background job first; raise clocks last.
