गाइड · डाउनटाइम और एरर

How to Fix a 504 Gateway Timeout: Causes, Logs and Timeouts

Find out why a proxy gave up waiting on your backend, how to spot slow queries and stuck workers, and which nginx, Apache, PHP and CDN timeouts to change.

लेखक: SiteDownCheck संपादकीय टीम · अपडेट: अक्टूबर 4, 2026 · 9 मिनट पढ़ने में

A 504 Gateway Timeout means a proxy or gateway waited for the server behind it and gave up before a response arrived. The backend may be slow, stuck, unreachable or simply doing too much work in one request. This guide explains how to find which hop timed out, how to locate the slow work, and how to change timeouts without hiding the real problem.

The code is defined in RFC 9110; the HTTP 504 reference has the short definition. The key point: the proxy is working correctly. It is the thing behind it that is not responding in time.

The mental model: every hop has a clock

In a typical stack, each layer has its own timeout, and the shortest one wins:

Browser (minutes) -> CDN (e.g. ~100 s) -> load balancer (often 60 s) -> nginx (60 s default) -> PHP-FPM / app (varies)

If PHP is allowed to run for 120 seconds but nginx waits only 60, nginx returns a 504 at 60 seconds while PHP keeps working in the background. That mismatch is behind a large share of confusing timeouts. Increasing a number in the wrong place does nothing, so first identify who timed out.

Find out who produced the 504

  1. Check the page and headers: curl -sI https://example.com/slow-page.
  2. Check the timing. A 504 that arrives after almost exactly 30, 60 or 100 seconds is a strong hint, because it matches a configured timeout. Measure it:
curl -s -o /dev/null -w 'status=%{http_code} connect=%{time_connect}s ttfb=%{time_starttransfer}s total=%{time_total}s\n' https://example.com/slow-page
  1. Read the logs on the gateway for the matching timeout entry:
sudo tail -n 100 /var/log/nginx/error.log | grep -i "timed out"

A typical nginx line looks like upstream timed out (110: Connection timed out) while reading response header from upstream. The phrase after "while" is the clue: connecting to upstream means the backend could not be reached in time; reading response header from upstream means the connection worked but no response arrived.

The HTTP स्टेटस चेकर shows the status and response timing from outside your network, and the वेबसाइट स्पीड टेस्ट reveals which requests on a page are slow.

Cause 1: the backend is slow on a particular request

Most 504s are not about the infrastructure; they are about a request doing too much work. Typical culprits:

  • A database query without a usable index, or one made inside a loop (the N+1 pattern).
  • A report, export, import or image processing job run synchronously in a web request.
  • A call to an external API (payment gateway, shipping, email, a plugin's licence server) with no timeout, so it blocks until the remote side answers.
  • A cache stampede: a cached item expires and many requests rebuild it at once.
  • Lock contention, such as a table lock or a long transaction.

Find the slow work

For PHP-FPM, enable the slow log in the pool config. It records a stack trace for any request exceeding the threshold, which usually names the exact function waiting:

; /etc/php/8.3/fpm/pool.d/www.conf
request_slowlog_timeout = 10s
slowlog = /var/log/php8.3-fpm.slow.log

Reload FPM, reproduce the issue, then read the file. For MySQL or MariaDB, turn on the slow query log temporarily:

SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 2;
SHOW FULL PROCESSLIST;

SHOW FULL PROCESSLIST during an incident shows which statements are running and for how long. In WordPress, tools such as Query Monitor identify plugins that run expensive queries or remote calls. For Node, Python and others, use the framework's profiler or add timing logs around outbound calls.

Cause 2: workers are saturated

If every worker is busy with slow requests, new ones wait in a queue and eventually time out. Symptoms: many requests slow at once, pm.max_children warnings in the PHP-FPM log, high load, and recovery when traffic drops. Check:

sudo journalctl -u php8.3-fpm --since "1 hour ago" | grep -i max_children
uptime
ps aux --sort=-%mem | head
sudo ss -s       # overall socket stats

The fix is to reduce time per request (caching, query fixes, moving heavy jobs to a queue) before increasing workers. See the worker sizing notes in fix 503 Service Unavailable.

Cause 3: the backend is unreachable or packets are being dropped

When the log says while connecting to upstream, the TCP connection did not complete within the connect timeout (60 seconds default in nginx via proxy_connect_timeout). That means the destination address is wrong, a firewall drops packets silently instead of rejecting them, the host is down, or the network path between proxy and backend is faulty. Test from the proxy machine itself:

nc -vz 10.0.0.11 9000
curl -v --max-time 10 http://10.0.0.11:8080/health
mtr -rw 10.0.0.11

From outside, the पोर्ट चेकर can confirm whether a public port accepts connections. A refused connection is a 502 matter, covered in fix 502 Bad Gateway, while a silent drop leads to a timeout.

Cause 4: DNS inside the proxy

nginx resolves hostnames in proxy_pass at startup unless you use a variable plus a resolver directive. If a backend's IP changes (common with cloud load balancers and containers), nginx keeps talking to the old address and times out. Reloading nginx refreshes the lookups, and using a resolver with a variable makes it dynamic.

Cause 5: CDN and load balancer limits

Layers in front of your server impose limits you may not control.

  • Cloudflare: the proxy waits for the origin's HTTP response for a default of 100 seconds, after which you see error 524 rather than a 504. The limit can be raised only on Enterprise plans. Long jobs should run in the background and be polled. See Cloudflare 520 to 526 errors explained, and use the Cloudflare एरर चेकर to identify the code.
  • Cloudflare 522 (connection timed out) is a different failure: the TCP connection to the origin was not established.
  • Cloud load balancers (AWS ALB, for example) have configurable idle timeouts, with the ALB default at 60 seconds. If your app legitimately needs longer, change the balancer setting and the web server setting together.
  • Serverless and managed platforms have hard per-request limits that you cannot exceed, so move long work out of the request cycle.

Changing timeouts safely

Raising timeouts is appropriate when a request is legitimately long, such as a large export, and you have already confirmed it is working rather than stuck. Change all relevant layers consistently, with the largest limits on the outside.

nginx

# proxy_pass upstreams
proxy_connect_timeout 10s;     # fail fast if the backend is unreachable
proxy_send_timeout    120s;
proxy_read_timeout    120s;    # default is 60s

# PHP-FPM via FastCGI
fastcgi_connect_timeout 10s;
fastcgi_read_timeout    120s;  # default is 60s

Check and apply:

sudo nginx -t && sudo systemctl reload nginx

Apache

# Overall request timeout (default 60s in recent versions)
Timeout 120

# For mod_proxy backends
ProxyTimeout 120

# For PHP-FPM through mod_proxy_fcgi
<FilesMatch "\.php$">
    SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost"
</FilesMatch>

PHP

max_execution_time governs PHP CLI differently from web requests: the CLI default is unlimited, while the web default is commonly 30 seconds. Under PHP-FPM, request_terminate_timeout in the pool file can kill a request regardless of max_execution_time. If PHP kills the script first, the proxy sees a closed connection and returns 502 rather than 504, so keep the order sensible: PHP limit lower than the proxy read timeout, which is lower than the CDN limit.

IIS

IIS has connectionTimeout and executionTimeout (for classic ASP.NET) settings, and ARR has its own proxy timeout. For ASP.NET Core behind IIS, check the request timeout in the hosting model as well as the app's configuration.

Long-running work: the real fix

If a request needs minutes, stop making the browser wait for it. Accept the request, put the job on a queue (Redis, a database table, a cloud queue), return 202 Accepted with a status URL, and let a worker process it. The page can poll the status or receive an email on completion. This approach scales better and avoids every timeout above.

Quick flow to follow

  1. Time the failing request with curl -w. Does it fail at a round number of seconds?
  2. Check the gateway log for "connecting to upstream" versus "reading response header".
  3. Connecting: test reachability from the proxy to the backend, review firewalls, backend state, DNS.
  4. Reading: enable slow logs, find the slow query or external call, check worker saturation.
  5. Does only one URL fail? Debug that code path. Does everything fail? Look at capacity and the backend itself.
  6. Align timeouts across layers only after you know the work is legitimate.

When to call your host

If you are on shared hosting and the timeout is on pages that used to work, ask whether the account hit CPU or I/O limits, whether the database server is overloaded, and whether anything changed on the server such as a PHP handler switch. On a VPS, ask the provider about noisy neighbours or network issues only after you have measured mtr loss and CPU steal time (st in top).

अगले कदम

Related tools and guides:

सामान्य प्रश्न

What is the default timeout that causes a 504 in nginx?

For both proxy_read_timeout and fastcgi_read_timeout, the default is 60 seconds. The connect timeouts default to 60 seconds as well. If your errors appear after about a minute, those values are the first suspects.

Is a 504 caused by my internet connection?

No. A 504 is generated by a server in the request path, so your connection did work well enough to receive it. If you are a visitor, wait and retry; if you own the site, the backend is not responding in time.

Should I just set all timeouts to a very high value?

No. Long timeouts let slow or hung requests occupy workers for longer, which can cause outages under load. Fix the slowness, fail quickly on external calls, and raise limits only for work that must run long.

Why do I get 504 on WordPress admin but not on the front end?

Admin pages and actions like imports, plugin updates, backups and bulk edits do heavier work and are usually not cached. Check for slow plugins or queries, and consider raising PHP and proxy timeouts for those paths only.

What is the difference between 504 and Cloudflare 524?

A 504 is the standard status for a gateway timeout. Cloudflare 524 is its own code meaning the connection to your origin succeeded but the origin did not return an HTTP response before Cloudflare's timeout, 100 seconds by default.

Get notified when this guide updates

Plus occasional practical tips on uptime and monitoring, nothing else. Unsubscribe anytime.

यह पेज सामान्य जानकारी है, जिसे हमारी संपादकीय टीम ने लिखा है और दस्तावेज़ीकरण बदलने पर अपडेट किया जाता है। सर्वर और प्रदाता अलग-अलग होते हैं, इसलिए बदलाव पहले सुरक्षित तरीके से जाँचें। देखें: संपादकीय नीति और अस्वीकरण.