WordPress troubleshooting

Maximum execution time exceeded

PHP stopped a script that had been running longer than it is allowed to. The limit did its job; the question is whether the job belonged in a web request.

Fatal error: Maximum execution time of 30 seconds exceeded

Short answer

Work out whether this is a web request or a background job. A page that needs more than thirty seconds has a problem to fix; an import that needs ten minutes needs to run somewhere a timeout does not apply.

Diagnosis

What causes it, most likely first.

Work down the list. Each check is written to rule its row in or out before you change anything, because the fixes below it are different and a guess costs more than a command.

CauseHow to checkFix
A bulk job running in the browserThe failure follows an action you started in wp-admin and stops at the same elapsed time each attempt.Run it from WP-CLI, where the limit does not apply, or in chunks that record progress and resume.
An update or install over a slow linkThe failure happens while downloading rather than while processing, and larger packages fail while small ones succeed.Raise the limit for the admin context, or install from the filesystem instead of over HTTP.
A slow outbound call inside a pageAn ordinary front-end URL is affected and the site depends on a third-party service that is having a bad day.Bound the outbound request with its own timeout and cache the result, rather than raising the script limit around it.
The limit applies where you did not expect itThe value differs between the CLI, the web request and cron - each context can carry a different one.Change it where the job actually runs. A raised web limit does nothing for a job executing under cron.
An infinite loopThe time is spent with no network and no database activity, and the same code path repeats in a profiler.Fix the loop. Raising the limit here only means the site is stuck for longer before it gives up.
Walkthrough

Fixing it, step by step.

Commands assume WP-CLI and shell access. Where you have neither, each step says what it is doing so it can be done from the dashboard or over SFTP instead.

  1. Find out which limit applies where

    The command line and the web request usually do not share a value.

    php -i | grep max_execution_time
    php -r 'echo ini_get("max_execution_time"), PHP_EOL;'
  2. Move the job to where the limit does not apply

    WP-CLI runs without a wall clock over it, which is why long jobs belong there.

    wp plugin install some-plugin --activate
  3. If it must run in a request, raise it for that path only

    Scoped to the admin context rather than to everything the site serves.

    wp config set WP_MEMORY_LIMIT '256M'
  4. Check whether the time is going outbound

    If the script is waiting on somebody else's server, the limit is not the thing to change.

    wp eval 'var_dump( wp_remote_get( "https://example.com", [ "timeout" => 5 ] ) );'
  5. Confirm it now finishes

    Run the same job again and watch it complete rather than assuming it will.

    time wp cron event run --due-now
On MagicWP

What the platform takes off the list.

Execution limits are raised for the admin and cron contexts and left where they belong for web requests, so an import has room to finish without also allowing a public page to run for minutes. WP-CLI is available on every plan for the jobs that should never have been in a browser tab, and scheduled work runs on a real scheduler rather than inside somebody's page load.

FAQ

Questions, answered.

Why is the limit thirty seconds?
It is PHP's default for web requests, and for a web request it is generous. No visitor waits thirty seconds. The limit is a problem only when a job that should not be in a request finds itself in one.
Does the limit apply to WP-CLI?
No. Command-line PHP runs with no execution time limit by default, which is exactly why long imports, exports and migrations belong there.
I raised it and the job still fails at the same point.
Then the limit you raised is not the one being enforced. Cron and web requests can carry different values, and a proxy in front can time out before PHP does.
Is this the same as a 504?
Related but not the same. This is PHP stopping itself; a 504 is the web server giving up on PHP. A long job can produce either, depending on which clock runs out first.
Related

If that was not it.

These fail in ways that look similar from the browser.