Skip to content

How to fix the 504 Gateway Timeout error in WordPress

A 504 comes from a server in front of WordPress, such as nginx or a CDN, that stopped waiting for an answer. The work behind it may have finished anyway. Find which request is slow, run a long job from the command line, and raise the wait only where a job needs it.

By
WP Ministry
Published
Tested on
WordPress 7.1.3, PHP 8.3.35

In short

  • A 504 is written by the server in front of WordPress. It waited for an answer and gave up.
  • The server in front stops waiting. It does not stop the work, so check whether the job finished before you run it again.
  • A long job run with WP-CLI does not pass through the web server, so no server in front is waiting on it.
  • When ordinary pages answer 504, something is slow. A longer wait only makes visitors wait longer.
  • nginx waits 60 seconds by default. A CDN has a wait of its own that you may not be able to change.

A 504 is not written by WordPress. It comes from a server that stands in front of it, such as nginx, a load balancer or a CDN. That server passed the request on, waited for an answer, and gave up before one came. A 502 means the server in front got an answer it could not use, and a 503 means a server said it cannot take requests for now. A 504 means no answer came in time.

The error deletes nothing. The server in front only stopped waiting, though. It did not stop the work. PHP learns that nobody is listening only when it next tries to send something, so a job that works in silence can run to the end after the 504 has been shown, and one that reports as it goes can be stopped partway. Look at what was done before you start the job again.

PHP has a limit of its own, 30 seconds by default, and a request stopped by that one shows Maximum execution time exceeded instead. By default on Linux, PHP's limit counts only the processor time the script itself uses, so a request that spends its time waiting on the database or on another server can run past 30 seconds on the clock and meet the wait in front first.

Work out which case you have

  • Read the error page. nginx's own page says "504 Gateway Time-out" with "nginx" beneath it. Apache's says "The gateway did not receive a timely response from the upstream server or application." A 504 page that carries Cloudflare's name means, by Cloudflare's account, that your server answered 504 and Cloudflare passed it on. Cloudflare's own Error 524 means your server gave it no answer within its wait, which is 125 seconds by default.
  • It happened during one job you started, such as an import, a backup or a bulk action, and the rest of the site works. Start with the first fix.
  • Ordinary pages show it, now and then or always. Something is slow. Go to the third fix.
  • Every page shows it, all at once. The server is in trouble. Go to the last fix. WordPress site down: a runbook for the first hour covers what to check meanwhile.

Where it goes wrong

A page request passes through each of these in turn. This one comes from the web server.

  1. Browser
  2. DNS
  3. HTTPS
  4. CDN or firewall
  5. Web server (this error comes from here)
  6. PHP
  7. WordPress
  8. Database and files

What causes it

  • One job takes longer than the server in front will wait

    Common

    An import, a backup or a bulk action in the dashboard can be long by nature. nginx gives up when PHP has sent it nothing for 60 seconds, unless it is set otherwise.

    Fix: Run the long job from the command line, or Do the job in smaller parts, or Raise the wait on a server you run

  • A plugin or a database query makes an ordinary page slow

    Common

    A page that needs a large database query, or runs slow code on every request, can take longer to build than the server in front waits.

    Fix: Find what makes an ordinary page slow

  • The page waits on another server

    Sometimes

    WordPress waits up to 5 seconds by default for each call it makes to another server, and a plugin can ask for longer. While it waits, the page waits.

    Fix: Find what makes an ordinary page slow

  • The server is short of resources

    Sometimes

    A server with too much to do answers every request slowly. Requests that finish in good time on a quiet day then run past the wait.

    Fix: Ask the host

  • The wait in front is shorter than the work needs

    Sometimes

    Each server in front has a wait of its own. A job that is healthy but long needs a longer one, or another way in.

    Fix: Raise the wait on a server you run, or Ask the host

How to fix it

Run the long job from the command line

  • Takes care
  • Low risk
  • About 15 minutes
  • Steps tested on WordPress 7.1.3

A command run with WP-CLI starts PHP from the server's command line. The job does not pass through the web server, so no server in front is waiting on it. PHP's own time limit is 0 on the command line by default, which means none.

  1. Step 1: See whether the job finished anyway

    Look for its result: the imported posts, a backup file with today's date, the new version numbers. If everything is there, nothing is left to do. If only part is, find out from the tool's documentation whether a second run carries on or starts over.

  2. Step 2: Connect over SSH and go to the site's folder

    How to use WP-CLI to manage a WordPress site covers connecting, checking that WP-CLI is installed, and backing up the database before a command that writes.

  3. Step 3: If the site also runs the job on a schedule, find its name

    A backup, a sync or a feed import that runs by itself each night is a scheduled event. List them:

    The first column, hook, is each job's name. Look for the one that carries the plugin's name.

    bash
    wp cron event list
  4. Step 4: Run it

    Put the job's name in place of hook-name. The command runs the next scheduled event for that hook and prints whatever the job reports. It ends with "Executed the cron event", the time it took, and "Success: Executed a total of 1 cron event." Keep the window open until then.

    bash
    wp cron event run hook-name
  5. Step 5: For any other job, use its own command

    WP-CLI has commands for updates, database exports and replacing an address. In the WP-CLI command builder you choose a job, fill in what it needs, and copy the command with its flags in place. A plugin can add commands of its own, so look in the documentation of the plugin that does the job.

Do the job in smaller parts

  • Easy
  • Low risk
  • About 20 minutes

With no SSH, make each request small enough to finish inside the wait.

  1. Step 1: Updates

    Update one plugin at a time, not all of them at once.

  2. Step 2: Bulk actions

    Select fewer items each time, so that each request finishes.

  3. Step 3: Imports and exports

    Split a large import file into several smaller ones, or use the tool's own setting for the size of a batch if it has one. WordPress's export screen can export posts or pages alone, and one range of dates at a time.

  4. Step 4: Backups

    If the backup plugin can split its work into smaller steps, turn that on.

Find what makes an ordinary page slow

  • Takes care
  • Low risk
  • About 30 minutes

An ordinary page that takes a minute to build has a fault. A longer wait in front would only make every visitor sit through it.

  1. Step 1: Note which addresses fail

    One page, one kind of page (a search, a report, the checkout), or only the dashboard. A page that fails only at busy hours points at the server, not the page.

  2. Step 2: Measure a page that still loads

    The page that answers 504 shows you nothing, so measure one like it that is slow but loads. How to reduce server response time (TTFB) in WordPress shows how to time a request in phases, with the cache and without it, and how to see which plugin, query or outside request a page spent its time on.

  3. Step 3: Look at calls to other servers

    WordPress waits up to 5 seconds by default for each call it makes to another server, and a plugin can ask for longer. A page that calls a service that is down waits out each call. If the slow pages all use one outside service, check whether that service is up.

  4. Step 4: Switch off what the measurements point at

    How to find and fix a WordPress plugin conflict covers switching plugins off and bringing them back in halves.

Raise the wait on a server you run

  • Advanced
  • Back up first
  • About 15 minutes

This is for a job that is healthy but long, on a server whose configuration you can edit. Where the host runs the server, use the last fix.

  1. Step 1: Confirm which wait ran out

    nginx writes a line with "upstream timed out" to its error log. If the log has no such line at the time of the 504, the wait that ran out belongs to something further forward, such as a load balancer or a CDN.

  2. Step 2: Add the line for your setup

    The first set of tabs below has the line. In nginx, put it in the site's server block, inside the location block that holds fastcgi_pass or proxy_pass. Both waits are 60 seconds by default, counted from the last time the server behind sent anything. In Apache, put it in the site's virtual host: it is not allowed in .htaccess. Unless it is set, ProxyTimeout takes the value of Timeout, which is 60 seconds by default.

  3. Step 3: Test the configuration, then reload

    Use the second set of tabs. The first command checks the files, and the second runs only if the check passed.

  4. Step 4: Run the job, then take the line out

    A long wait lets a stuck request hold on to the server for five minutes at a time. If the job now ends in "There has been a critical error on this website", PHP's own limit was reached, and the page linked at the top of this one covers raising it.

fastcgi_read_timeout 300s;
The line to add. Use the one that matches how requests reach PHP.
sudo nginx -t && sudo nginx -s reload
Test the configuration, then reload.

A CDN's wait is the CDN's to set. Cloudflare's is 125 seconds by default, and its documentation says that only Enterprise customers can raise it, to 6,000 seconds at most. For requests that regularly need longer, Cloudflare's own suggestion is to move them to a subdomain that it does not proxy.

To undo it: Remove the line and reload the server.

Ask the host

  • Easy
  • No risk
  • About 15 minutes

Where you cannot read the server's logs or edit its configuration, the host can.

  1. Step 1: Write down what happened

    The full address that failed, the exact time with your time zone, the words on the error page, and what you were doing.

  2. Step 2: Ask questions that have an answer

    Ask which server answered 504 and how long it waits. Ask what the error log shows for that request, and whether the server was under heavy load or the account had reached a limit. If one long job is the cause, ask whether the wait can be raised for your site.

WordPress hosting problems: how to tell whether the fault is the host or the site has a message to copy, and a section on when the plan itself is the problem.

When to get help

If ordinary pages still answer 504 with every plugin switched off, or the same job fails from the command line too, a longer wait will not help. Something on the server is slow or stuck, and finding it means reading the server's own logs, which on most hosting only the host can open.

Common questions

Will raising PHP's max_execution_time fix a 504?

No. That setting is PHP's own limit on how long a script may run. A 504 means the server in front stopped waiting first, so raising PHP's limit changes nothing a visitor sees.

Why did the job finish even though I saw a 504?

Because the server in front gave up on the answer, not on the work. PHP's manual says PHP does not detect that the connection has gone until it tries to send something, so a job that sends nothing until the end runs on.

Is a 504 a problem with my computer or my connection?

Rarely. MDN's note is that the exceptions are faults in the visitor's own network setup, such as a VPN or a proxy, when the site works for other people. Try from a phone on mobile data. If the 504 is there too, the fault is on the site's side.

More on this subject

Would you rather we fixed it?

Quick Fix is $49. One issue, one site, up to about an hour. No fix, no fee. 30-day warranty. It starts with a free diagnosis.