Skip to content
ThemesIonic — home
Troubleshooting

Fixing the Maximum Execution Time Error

The fatal names a file and a line, and that line is where PHP was when the clock ran out — not necessarily what was slow. Raising the limit buys time; reading the trace tells you what was spending it.

Updated 4 min read intermediate

PHP stopped the request at the time limit and reported where it was, not what was slow. "Fatal error: Maximum execution time of 30 seconds exceeded in /path/to/file.php on line N" has two halves. The limit is a PHP setting you can raise. The location is a clue about what consumed the time, and raising the limit without reading it turns a 30-second failure into a 300-second one.

Raise the limit where it takes effect

max_execution_time can be changed by a running script with set_time_limit(), which is why snippets for wp-config.php exist — but hosts commonly disable the function, and the web server has its own timeout that ends the request regardless of PHP's. The settings that hold:

Setup Where
Control panel hosting PHP settings / PHP version selector
PHP-FPM php.ini or .user.ini in the site root: max_execution_time = 300
Apache with mod_php .htaccess: php_value max_execution_time 300
PHP-FPM pool request_terminate_timeout must be at least as high, or FPM kills the worker first
Nginx in front of FPM fastcgi_read_timeout 300; as well, or nginx returns 504 first
Apache as proxy to FPM ProxyTimeout or Timeout directive

The last two rows are why "I raised it and now get a 504 instead" happens: PHP continued, the web server gave up waiting. Match the layers. The procedure for .user.ini versus .htaccess is the same as for upload limits, and a php_value line on a server without mod_php causes a 500.

Now read the error

The file and line are where the limit hit. Trace upward:

  • wp-db.php or class-wpdb.php — a query was running. Something above it issued it; a plugin querying inside a loop is the typical pattern. The slow query log on the database, or a query monitor plugin on a page that does not time out, shows which query and how many times.
  • class-wp-filesystem-direct.php, class-pclzip.php, file.php — an update or install was copying or unzipping. Disk speed, a huge plugin, or a host limit below the 300 seconds core requests. Update over WP-CLI, which has no web limit.
  • class-http.php, class-requests.php — an outbound HTTP call hung. A plugin calling an API that did not answer; the http_request_timeout filter or the plugin's own timeout is too generous, and the remote service is the slow part.
  • A plugin's own file — the plugin's code is the loop. Deactivate it and reproduce; if the time drops, the plugin is the cause, and plugin conflict testing confirms it.
  • wp-cron.php or wp-includes/cron.php — a scheduled task ran inside a visitor's request and took too long. Moving cron to a real scheduler takes it out of page loads entirely.
  • An import, migration or regeneration tool — the task genuinely needs more than 30 seconds. Those tools usually batch; if yours does not, run it over WP-CLI.

Imports and bulk tasks

A CSV import of ten thousand products, a thumbnail regeneration, a search-index rebuild — these are the honest cases for a high limit. Even so, the limit is per request, and a tool that does everything in one request will hit any limit on a large enough site. Prefer tools that process in batches with a progress indicator, or run the task from the command line where max_execution_time is unlimited by default. An admin that is slow in general, rather than during one task, is a different diagnosis.

When the time is not CPU

A request can take 30 seconds while doing nothing: waiting on a locked database table, a remote API, a DNS lookup that times out, or a file lock. Raising the limit lets it wait longer. The location in the error separates waiting from working — an HTTP class or a sleep-like lock wait versus a loop in plugin code — and only the second is fixed by optimisation.

Verify

Reproduce the action that timed out after raising the limit. If it now completes, note how long it took: a task that needs 200 seconds will fail again when the site grows. If the error moved to a different file and line, the first bottleneck is gone and the next one is showing; the same reading applies. Then lower the limit back toward a sane value — 60 or 120 — once the slow task is batched or moved to the command line, so a runaway request cannot hold a PHP worker for five minutes.

Frequently asked

Many hosts list set_time_limit in disable_functions, and even where it works PHP-FPM's request_terminate_timeout kills the worker regardless of what the script asked for. The reliable place is php.ini, .user.ini, or the hosting panel, with the web server's own timeout raised to match.
No. The line is wherever PHP happened to be when the limit hit, which is usually inside a database call or a loop in core. What is slow is the caller: a plugin running a query thousands of times, an import, or an update extracting a large zip. The stack above that line names it.
Updates download, unzip and copy files inside one request. Core raises the limit to 300 seconds for its own updater, but a host that caps execution time below that, or a slow disk, still times out. Updating over WP-CLI runs without the web limit.

Related guides