ERROR · 21 · VERIFIED 2026-10allwpcare.com/errors/504-gateway-timeout/
Errors / 504-gateway-timeout

504 Gateway Time-out in WordPress

The server in front of PHP gave up waiting. Read its error log, raise fastcgi_read_timeout or ProxyTimeout for the slow page, or make the slow job shorter.

The message you see
1−504 Gateway Time-out (nginx) / Gateway Timeout (Apache)
Last verified Oct 2026Tested with WordPress 7.1Applies to WordPress 7.1 (tested on nginx with PHP-FPM, and Apache with PHP-FPM) · PHP 7.4+

Why it happens

  • One request takes longer than the proxy is willing to wait. nginx waits 60 seconds by default for PHP-FPM to send anything. An import, a backup, a big export or a slow call to another website can pass that.
  • The proxy's limit was set low, by you or by your host. A host's limit can be shorter than nginx's default, and you cannot see it in WordPress.
  • PHP-FPM has no free worker, or the database is stuck, so even a light request waits. The log line looks the same; the access log shows that normal pages are slow too.
  • The 504 is not from your server at all but from a CDN, load balancer or host proxy in front of it. Its limit is separate and cannot be changed in wp-config.php.

How to fix it

Try the fixes in this order. Each one is independent: stop as soon as the error is gone.

FIX 01

Find out which server sent it

  1. WordPress never writes a 504 page. The page is plain and unstyled, with no theme and no WordPress text. nginx titles it "504 Gateway Time-out" and names itself under a line: nginx/1.31.8. Apache says "Gateway Timeout" and ends with Apache/2.4.69 (Debian) Server at localhost Port 8962. Many hosts hide that last line.
  2. Open your browser's developer tools, Network tab, click the failed request and look at the Server response header. nginx or Apache means your own server. The name of a CDN or other service means the 504 came from that service, and its timeout is the one to look up.
  3. A page with your theme around it and the words "There has been a critical error on this website" is a different problem: PHP failed inside WordPress. See the critical error page.
FIX 02

Read the proxy's error log

  1. The browser page says nothing about the reason. The log does. On nginx it is usually /var/log/nginx/error.log. Hosts with a control panel show it under Logs or Error log.
  2. A real timeout on nginx logs: upstream timed out (110: Operation timed out) while reading response header from upstream, followed by the request, for example request: "GET /?sleep=12 HTTP/1.1". The request in the line is the slow page.
  3. On Apache with PHP-FPM, the error log has: (70007)The timeout specified has expired: [client ...] AH01075: Error dispatching request to :8962: (polling).
  4. If the line says Connection refused or upstream prematurely closed connection instead, PHP-FPM is down or crashed. That is a 502, not a timeout. Use the 502 Bad Gateway page.
FIX 03

Find the slow request

  1. The request in the log line tells you which URL is slow. A URL under /wp-admin/ such as admin-ajax.php, import.php or update.php points at an admin job. /wp-cron.php or /wp-json/ points at a scheduled task or a REST call.
  2. If every page is slow, not just one, the cause is not one plugin. Look at load on the server, the database, or the number of PHP workers.
  3. To see how long PHP really takes, add access.format = "%{%H:%M:%S}t %m %r%Q%q status %s took %{seconds}ds" to the PHP-FPM pool file and restart PHP-FPM. On my test site it logged GET /index.php?sleep=12 status 200 took 12.242s for a request the visitor saw as a 504.
  4. To find the plugin, turn plugins off one at a time and repeat the slow action, or turn on the debug log and read the WordPress debug log guide.
FIX 04

Raise the proxy's timeout for the slow page (nginx)

  1. In the nginx site file, find the location ~ \.php$ block that has fastcgi_pass. Add fastcgi_read_timeout 60s; or a larger value, for example fastcgi_read_timeout 300s;.
  2. To keep the short limit for visitors and give only the admin a long one, add a second block above it: location ~ ^/wp-admin/.*\.php$ { ... fastcgi_read_timeout 300s; } with the same include and fastcgi_pass lines. In my test, a front-end request with sleep=8 got a 504 after 5.0 seconds under a 5 second limit, and /wp-admin/admin-ajax.php?sleep=8 answered after 8.0 seconds.
  3. Check the file and reload: nginx -t then nginx -s reload. With a 30 second limit, my 12 second request returned status 200 after 12.3 seconds instead of a 504.
  4. The limit is a wait for the next bit of data, not for the whole page. nginx documents it as the time between two successive reads. A page that sends output regularly can run longer than the number.
  5. Also raise PHP's max_execution_time above your new proxy limit if the job is busy, otherwise PHP stops it first. See below, and maximum execution time exceeded.
FIX 05

Raise the proxy's timeout (Apache with PHP-FPM)

  1. This only applies when Apache hands PHP to PHP-FPM through mod_proxy_fcgi. With PHP as an Apache module (mod_php) there is no gateway, so Apache cannot answer 504 for a slow script. I checked: a script that ran past max_execution_time on mod_php ended with a 500 after 3.1 seconds.
  2. In the Apache config, set ProxyTimeout 300. Its default is the value of Timeout, which is 300 in the Debian config I used.
  3. My test used ProxyTimeout 5 and got "Gateway Timeout" after 5.0 seconds. With ProxyTimeout 30, the same 12 second request returned 200 after 12.1 seconds. Restart Apache after the change.
FIX 06

On managed hosting, ask for the limit

  1. On a host where you cannot edit nginx or Apache, the limit is theirs. Open a ticket with the URL, the time of the failure and how long the action takes, and ask what their proxy timeout is and whether it can be raised for that page.
  2. Do not raise max_execution_time in the hope it will help. It does not move the proxy's clock.
FIX 07

Make the slow request shorter

  1. A longer limit hides the problem and holds one PHP worker for longer. If the job is an import or export, split it into smaller files or date ranges.
  2. If the plugin has a WP-CLI command, run it there. PHP on the command line has no time limit: on my test site php -i under CLI showed max_execution_time => 0, and there is no proxy in the way.
  3. If the slow part is a call to another website, see cURL error 28. That website is the thing to fix or to skip. PHP waits for it and the proxy's clock keeps running.
FIX 08

Check before you try again

  1. A 504 does not stop PHP. In my test the visitor got a 504 after 5 seconds, and PHP finished the request with status 200 at 12.2 seconds. An import, a save or an update may have completed after you saw the error.
  2. Before you click again, look at the result: the imported posts, the plugin version, or the saved setting. Running a non-repeatable job twice can import everything twice.

A 504 means a server that passes requests on to PHP waited too long and gave up. PHP is not the one that sent it, and WordPress did not write the page. The fix is in the limit of that server, or in making the request shorter.

What you see#

The browser shows a short, plain page. It has no theme and no WordPress text, so it looks different on each server:

A white page with a centred bold heading: 504 Gateway Time-out. Below a grey rule, the line nginx/1.31.8.
nginx, as I captured it from a WordPress 7.1.4 site served through nginx and PHP-FPM. The status line is HTTP/1.1 504 Gateway Time-out.
A white page with the left-aligned heading Gateway Timeout, then the line: The gateway did not receive a timely response from the upstream server or application. Below a grey rule, in italics: Apache/2.4.69 (Debian) Server at localhost Port 8962.
Apache with PHP-FPM behind it. The heading says Gateway Timeout, without a hyphen, and the status line is HTTP/1.1 504 Gateway Timeout.

The two servers use different words. Search engines and guides mix them up, so match the page you see to the right row:

Where it was capturedStatus linePage headingLog line
nginx 1.31.8 + PHP-FPM504 Gateway Time-out504 Gateway Time-outupstream timed out (110: Operation timed out) while reading response header from upstream
Apache 2.4.69 + PHP-FPM (mod_proxy_fcgi)504 Gateway TimeoutGateway Timeout(70007)The timeout specified has expired ... AH01075: Error dispatching request ... (polling)

The nginx log text is Operation timed out, not Connection timed out, in the nginx image I used on Linux. The number 110 is the same code in both wordings.

WordPress's own list of status texts, get_status_header_desc() in wp-includes/functions.php, says "Gateway Timeout" for 504. I searched the 7.1.4 files for 504 and found no place where core sends one. The other hits are the HTTP library's names for a 504 answer that WordPress receives from another site.

How it works#

With nginx or Apache in front of PHP-FPM, the visitor never talks to PHP directly. The web server forwards the request and waits. If PHP sends nothing for longer than the server's limit, the server closes the connection and answers 504 itself.

Four stacked cards. 1, the proxy clock: nginx fastcgi_read_timeout 60 seconds by default, Apache ProxyTimeout equal to Timeout; when it runs out the visitor gets 504 and PHP keeps going. 2, PHP-FPM request_terminate_timeout, off by default; when it runs out the worker is killed and the proxy says 502. 3, PHP max_execution_time, 30 seconds by default, counting busy time only; when it runs out WordPress shows the critical error with status 500. 4, the shortest clock decides: in the lab a 12 second request behind a 5 second proxy gave a 504 after 5.0 seconds, and PHP finished with 200 at 12.2 seconds.
Up to three clocks run on one request. Whichever is shortest decides the message.

I tested each clock on one site: WordPress 7.1.4, PHP 8.3 with PHP-FPM, nginx in front. A small test plugin made the page slow, either by sleep() or by a busy loop. The proxy limit was 5 seconds:

RequestPHP limitsWhat the visitor gotWhat PHP did
Sleeps 12 smax_execution_time 30504 after 5.0 sFinished with 200 after 12.2 s
Busy loop 8 smax_execution_time 60504 after 5.0 sFinished with 200 after 8.3 s
Busy loop 8 smax_execution_time 3500 after 3.1 s (critical error page)Maximum execution time of 3 seconds exceeded in the log
Sleeps 12 smax_execution_time 3, proxy 30 s200 after 12.3 sSleeping does not count
Sleeps 8 srequest_terminate_timeout 3 s502 after 3.9 sWorker killed with SIGTERM
Sleeps 12 srequest_terminate_timeout 8 s504 after 5.0 sProxy was faster

A 504 is therefore a message about waiting, not about work. This is why the usual advice to raise the PHP memory limit or max_execution_time often does nothing: PHP is not the one that gave up. See maximum execution time exceeded for what happens when PHP's own clock runs out first, and 502 Bad Gateway for the killed-worker case.

The proxy's request log shows it#

Here is what my nginx wrote for the first row of the table, and what PHP-FPM wrote about the same request:

nginx error.log
2026/10/30 07:29:37 [error] 23#23: *7 upstream timed out (110: Operation timed out) while reading response header from upstream, client: 172.23.0.1, server: , request: "GET /?sleep=12 HTTP/1.1", upstream: "fastcgi://172.23.0.12:9000", host: "localhost:8961"
PHP-FPM access log
07:29:32  GET /index.php?sleep=12  status 200  took 12.242s

PHP started the request at 07:29:32, nginx gave up at 07:29:37, and PHP finished anyway. The visitor was gone, but the work was done.

It also breaks the editor and other background calls#

A request from the block editor or a plugin's screen is a normal request, so a slow one gets the same page. The editor expects JSON, and a 504 page is HTML. I made a slow REST request through the proxy:

Terminal
curl -s -D - "http://localhost:8961/?rest_route=/wp/v2/types&sleep=8"
Output
HTTP/1.1 504 Gateway Time-outContent-Type: text/html...<html><head><title>504 Gateway Time-out</title></head>

This is the usual reason behind "Updating failed. The response is not a valid JSON response." See that page to tell it apart from other causes.

What the default limits are#

SettingWhereDefault
fastcgi_read_timeoutnginx, between two reads from PHP-FPM60 s
ProxyTimeoutApache mod_proxy, including proxy_fcgiThe Timeout value (300 s in the Debian config I used)
request_terminate_timeoutPHP-FPM pool0, which is off
max_execution_timePHP, web requests30 s

I confirmed the nginx default: a config with no fastcgi_read_timeout line gave a 504 after 60.05 seconds for a 70 second request.

If a long update triggers it, updating plugins safely shows how to run updates one at a time.

If it only happens sometimes#

A request that is slow at busy hours and normal at quiet hours usually waits for something shared, not a plugin: no free PHP-FPM worker, a busy database, or a slow outside service. Raising the timeout makes people wait longer for the same slow answer. Check the access log for slow requests of every URL, and ask your host whether PHP workers run out.

Sources

  1. 504 Gateway Timeout - HTTP status, MDN · what the status means: a gateway got no response in time
  2. nginx ngx_http_fastcgi_module: fastcgi_read_timeout · 60 second default, measured between two reads
  3. Apache mod_proxy: ProxyTimeout · default is the Timeout value
  4. PHP manual: FPM configuration, request_terminate_timeout · kills the worker; off by default
Newsletter

One email when something breaks or changes.

New plugins and re-tested guides, about twice a month. Never a sales pitch.