How to Fix 504 Gateway Timeout on WordPress (Nginx & Apache)

504 Gateway Timeout on WordPress is a server-side error. Here is how to diagnose it on Nginx and Apache, fix PHP-FPM timeouts, and stop it happening again.

Dobromir Dechev
Dobromir WordPress agency owner

Quick answer

A 504 Gateway Timeout on WordPress means the web server (Nginx or Apache) gave up waiting for PHP-FPM to respond — fixing it requires increasing the fastcgi_read_timeout in Nginx or the ProxyTimeout in Apache, and identifying the slow query or plugin causing the long execution time.

A 504 Gateway Timeout means your web server (Nginx or Apache) sent a request to an upstream service - usually PHP-FPM or a proxy - and that upstream service took too long to respond. The server gave up waiting and returned an error to the visitor.

Unlike a 500 error (which usually means PHP crashed), a 504 means PHP is still running - it is just taking longer than the configured timeout. This distinction matters for diagnosing it.

Common scenarios where 504s appear on WordPress sites:

  • A page that runs a slow database query (large WooCommerce stores, poorly optimised posts queries)
  • A plugin making an external HTTP request that hangs (payment gateways, social media feeds, weather widgets)
  • Too many concurrent requests overwhelming PHP-FPM's worker pool
  • Running WP-CLI commands or bulk operations that legitimately take a long time
  • A misconfigured proxy chain (Nginx > PHP-FPM, or Nginx > Apache > PHP-FPM)

Step 1 - Identify where the timeout is configured

A 504 can come from several layers. Check each timeout in order:

Nginx read timeout (most common)

If you run Nginx as a reverse proxy in front of PHP-FPM, the relevant directive is fastcgi_read_timeout:

location ~ \.php$ {
    fastcgi_pass   unix:/var/run/php/php8.1-fpm.sock;
    fastcgi_read_timeout 120;  # seconds
    include fastcgi_params;
}

The default is 60 seconds. Increase it to 120 or 180 for sites with heavy processing.

After editing nginx config, always test before reloading:

sudo nginx -t
sudo systemctl reload nginx

PHP-FPM timeout

PHP-FPM has its own request timeout. Edit your PHP-FPM pool config (usually /etc/php/8.1/fpm/pool.d/www.conf):

request_terminate_timeout = 120

This is the maximum time a PHP request is allowed to run. If your operation legitimately takes longer (bulk imports, PDF generation), increase it. But do not set it to 0 (unlimited) on production - that allows runaway scripts to hold FPM workers indefinitely.

sudo systemctl restart php8.1-fpm

PHP max_execution_time

Set in php.ini or per-site:

max_execution_time = 120

Or in .htaccess (Apache):

php_value max_execution_time 120

Or in wp-config.php:

set_time_limit( 120 );

Note: set_time_limit() resets the timer each time it is called and excludes time spent in external calls - so a script can run longer than the value if it is doing network I/O.

Apache ProxyTimeout (if using Apache as a reverse proxy)

ProxyTimeout 120

Load balancer / CDN timeout

If you have Cloudflare, AWS ALB, or another load balancer in front of your server, it also has its own timeout. Cloudflare's default proxy timeout is 100 seconds - requests that take longer than that will 524 (their custom code for origin timeout). Increase this in Cloudflare's Route Settings, or better, make the origin faster.

Step 2 - Find the slow request

Check your Nginx access log to identify which URL is timing out:

sudo grep "504" /var/log/nginx/access.log | tail -20

This shows you the URL, response time, and timestamp. A pattern like /wp-admin/admin-ajax.php timing out usually means a plugin's AJAX handler is running a slow query.

Enable Nginx response time logging to pinpoint slow requests:

log_format timed '$remote_addr [$time_local] "$request" $status '
                 '$body_bytes_sent $request_time';
access_log /var/log/nginx/access.log timed;

Any $request_time above your timeout threshold is a suspect.

Step 3 - Profile the slow database query

Most legitimate 504s on WordPress are caused by a slow SQL query. Enable MySQL slow query logging:

SET GLOBAL slow_query_log = 1;
SET GLOBAL long_query_time = 2;       -- log queries taking > 2 seconds
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';

Or persistently in /etc/mysql/mysql.conf.d/mysqld.cnf:

slow_query_log       = 1
slow_query_log_file  = /var/log/mysql/slow.log
long_query_time      = 2
log_queries_not_using_indexes = 1

After a few minutes of traffic, read the log:

sudo tail -100 /var/log/mysql/slow.log

You will see queries like:

Query_time: 8.432  Lock_time: 0.000  Rows_sent: 1500  Rows_examined: 2500000
SELECT * FROM wp_postmeta WHERE meta_key = '_sku';

A Rows_examined value much higher than Rows_sent means the query is doing a full table scan. Add an index or rewrite the query.

For WordPress specifically, the most common slow queries are:

  • wp_postmeta scans (WooCommerce product meta without indexes)
  • wp_options with autoload = 'yes' rows accumulating
  • Custom meta queries using LIKE '%value%' which cannot use indexes

Use EXPLAIN on the slow query to understand what is happening:

EXPLAIN SELECT * FROM wp_postmeta WHERE meta_key = '_sku';

Step 4 - Identify external HTTP requests causing timeouts

WordPress plugins frequently make outgoing HTTP requests - to payment gateways, weather APIs, social feeds, license servers. If any of these are slow or down, the PHP process hangs waiting, and you get a 504.

To diagnose, add this to wp-config.php temporarily:

define( 'WP_DEBUG',     true );
define( 'WP_DEBUG_LOG', true );

Then check the debug log for HTTP timeouts. You can also use the Query Monitor plugin, which shows all external HTTP requests and their duration on any admin page.

A quick way to test if a specific external URL is slow from your server:

curl -o /dev/null -s -w "%{time_total}\n" https://api.example.com/endpoint

If the external service is reliably slow, the fix is to:

  1. Add a shorter timeout to the WordPress HTTP API call: add_filter( 'http_request_timeout', fn() => 5 );
  2. Cache the API response with a transient so it is only fetched once every hour
  3. Replace the plugin with one that does not make blocking external requests on page load

Step 5 - PHP-FPM worker exhaustion

If your site gets sudden traffic spikes, PHP-FPM may run out of available workers. New requests queue up, then time out at the Nginx level. Check FPM status:

# Enable status page in pool config first
pm.status_path = /status

Then:

curl http://127.0.0.1/status

You will see active processes, idle processes, and the queue length. If listen queue is consistently above 0, you are worker-constrained.

Increase the max children in your FPM pool config:

pm = dynamic
pm.max_children = 50         ; max concurrent PHP processes
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.max_requests = 500        ; recycle workers to prevent memory leaks

The right value for pm.max_children depends on your server RAM. Each PHP-FPM worker uses roughly 30-60 MB. On a 2 GB RAM VPS with MySQL also running, 20-25 children is a reasonable maximum.

Step 6 - Check for runaway cron jobs

WP Cron tasks that run a heavy operation (sending 1000 emails, regenerating all thumbnails) can monopolise PHP-FPM workers for minutes. When too many cron tasks stack up, they starve normal page requests of workers.

Check what is in the cron queue:

wp cron event list --format=table

If there are hundreds of pending events, something is broken. Clear stuck events:

wp cron event delete --all

Then identify and fix the plugin that is generating excessive cron jobs.

Preventing 504s long-term

Use a page cache

A full-page cache (WP Rocket, FlyingPress, LiteSpeed Cache, or server-side Nginx FastCGI cache) serves cached HTML without invoking PHP at all. Cached pages cannot 504. This is the single most effective protection against timeout errors under traffic spikes.

Move slow operations to background jobs

Any operation that might take more than 2 seconds should not run synchronously on page load. Use Action Scheduler (bundled with WooCommerce) or a plugin like WP Background Processing to queue slow tasks and run them via cron.

Use a managed host

Kinsta and Cloudways pre-configure PHP-FPM timeouts appropriately for WordPress, provide per-site Redis caches, and monitor for slow query patterns. The majority of 504 issues I have seen in the wild are on self-managed VPS setups where timeouts were left at defaults.


Quick reference

LayerDirectiveDefaultWhere to change
Nginxfastcgi_read_timeout60snginx site config
PHP-FPMrequest_terminate_timeout0 (unlimited)pool .conf
PHPmax_execution_time30sphp.ini / .htaccess
Apache proxyProxyTimeout300shttpd.conf
CloudflareRoute timeout100sCloudflare dashboard

Frequently Asked Questions

What causes a 504 gateway timeout on WordPress?
A 504 error means your web server sent a request to PHP-FPM (or another upstream service) and PHP took longer to respond than the configured timeout allows. Common causes include slow database queries on large WooCommerce stores, plugins making external HTTP requests that hang, or PHP-FPM running out of worker processes under high traffic.
How do I fix 504 timeout on WordPress with Nginx?
Open your Nginx server block configuration and increase the fastcgi_read_timeout directive — the default is 60 seconds, try 300. Also set fastcgi_connect_timeout and fastcgi_send_timeout to matching values. Reload Nginx with nginx -s reload. If the timeout only affects one slow page, the better long-term fix is to optimise the query or plugin causing the delay.
Is a 504 error a WordPress problem or a server problem?
It is a server-side problem, not a WordPress problem. WordPress itself is not returning an error — PHP is simply taking too long to generate a response. The 504 is reported by Nginx or Apache, not by WordPress. That said, a WordPress plugin or an unoptimised database query is usually what causes PHP to run slowly enough to trigger the timeout.
How do I stop WooCommerce from causing 504 timeouts?
WooCommerce 504s are usually triggered by slow database queries on large product or order tables, or by payment gateway API calls timing out. Install Query Monitor to identify slow queries and add database indexes where needed. For payment gateway timeouts, check the gateway's API status page and increase the HTTP timeout constant in wp-config.php: define('WC_GATEWAY_TIMEOUT', 30).

Was this article helpful?