You click "Import" on a big CSV of products, or a plugin update kicks off a database migration, and the page just... sits there. The loading spinner spins, and spins, and then the browser finally gives up with a blank white screen and one line buried in the HTML: "Fatal error: Maximum execution time of 30 seconds exceeded in /home/username/public_html/wp-includes/something.php on line 123." Nothing crashed exactly — PHP just refused to keep running.

This is a different animal from the classic "Allowed memory size exhausted" error. That one is about how much RAM a script can grab. This one is about how long PHP will let a single request run before it pulls the plug, no matter how much memory is left. Mixing the two up is the most common reason people raise the wrong setting and wonder why the error keeps coming back.

Symptom: What This Error Looks Like

A few patterns give it away:

  • The exact text "Maximum execution time of X seconds exceeded" in a white-screen fatal error, usually pointing at a file inside wp-includes, wp-admin, or a plugin folder
  • It only happens during long-running actions — bulk imports, plugin/theme installs from a slow source, large database migrations, PDF or image batch processing, or a WooCommerce order sync
  • Quick page loads work fine; the error only shows up on the specific screen doing heavy lifting
  • Sometimes there's no visible error at all — the request just times out at exactly 30 or 60 seconds and the browser shows a generic "504" or a blank page, especially behind a reverse proxy or CDN

If the timer is suspiciously consistent — always dying at almost exactly the same number of seconds — that's your confirmation it's max_execution_time, not memory.

Cause: Why PHP Cuts the Script Off

PHP has a setting called max_execution_time that puts a hard ceiling on how many CPU-seconds a single script is allowed to run. It exists to stop a runaway or infinite-loop script from tying up a server forever. On most shared cPanel hosting the default is 30 seconds; some VPS setups default to 60 or 120.

The catch is that 30 seconds is plenty for a normal page load, but nowhere near enough for:

  • Importing a few thousand rows through a CSV/XML importer plugin
  • A theme or plugin installer pulling a large zip from a slow remote server
  • WP-CLI-style bulk operations triggered from the admin UI instead of the command line
  • Database search-and-replace across a large table during a migration
  • Image regeneration for hundreds of media items after a theme change

Just like memory limits, execution time isn't set in one single place. There are usually three layers, and the lowest one wins:

LayerWhere it livesTypical default
PHP max_execution_timephp.ini / MultiPHP INI Editor / .user.ini30 seconds
Web server timeoutApache/Nginx/LiteSpeed config, or a reverse proxy in frontOften 60–120 seconds, but can be lower
Browser/CDN idle timeoutCloudflare, a load balancer, or the browser itselfVaries, sometimes as low as 30 seconds too

Raising max_execution_time to 300 seconds does nothing if a proxy in front of the server still kills the connection at 60. That's why "I already fixed this" tickets are so common — one layer got raised, the others didn't.

Fix: Raising the Limit the Right Way

Start with the setting that's actually cheapest and safest to change, then work outward only if you still hit the wall.

1. Check your current limit

Create a file called phpinfo.php in your site root with:

<?php phpinfo(); ?>

Visit it in the browser, search the page for max_execution_time, note the value, then delete the file immediately — leaving phpinfo() exposed is a real information-disclosure risk.

2. Raise it in cPanel's MultiPHP INI Editor

This is the cleanest way on shared/reseller hosting, because it applies at the account level without touching code:

  1. Log in to cPanel → MultiPHP INI Editor
  2. Select your domain from the dropdown
  3. Switch to Editor Mode
  4. Find or add max_execution_time = 300
  5. Click Apply

300 seconds (5 minutes) is a sane ceiling for most imports. Don't set it to 0 (unlimited) on shared hosting — a genuinely broken loop will then hang forever and eat CPU quota instead of failing fast.

3. If you don't have MultiPHP access, use .user.ini or php.ini

Drop this in a .user.ini file in your site's public root (works on most PHP-FPM setups, no restart needed — changes apply within a few minutes):

max_execution_time = 300
max_input_time = 300

On older mod_php setups you may need a php.ini in the same folder, or an .htaccess entry instead:

php_value max_execution_time 300

Note that php_value in .htaccess will throw a 500 error on PHP-FPM/php-cgi setups — check which handler your account uses before adding it.

4. Set it in wp-config.php as a fallback

Add this near the top of wp-config.php, right after the opening <?php tag:

set_time_limit(300);

This only works if PHP's safe_mode is off (it is, on virtually every modern host) and won't override a hard limit set at the server level, but it's a useful belt-and-suspenders line for WordPress-specific timeouts.

5. Check the web server and proxy layer

If you raised PHP's limit to 300 seconds and the request still dies around 60, something in front of PHP is cutting it off first:

  • Nginx: look for fastcgi_read_timeout and proxy_read_timeout in the site config — both need to be at least as high as your PHP limit
  • Apache: check Timeout in the vhost or httpd.conf
  • Cloudflare or another CDN/proxy: these often enforce their own 100-second cap on the free/pro tiers that you can't raise — for imports this large, run them via WP-CLI over SSH instead, bypassing the browser entirely

On a SkyServer VPS you control the full stack, so all three layers are yours to adjust. On shared hosting, MultiPHP plus .user.ini usually covers it; open a support ticket if the web server timeout also needs raising.

Prevention: Stop Hitting the Wall in the First Place

  • Run big jobs from the command line, not the browser. WP-CLI (wp import, wp search-replace, wp plugin update --all) isn't bound by PHP's execution time limit the same way HTTP requests are, and it's far more reliable for anything that takes more than a few seconds.
  • Batch large imports. Most import plugins let you process in chunks (500 rows at a time, for example) instead of one giant request — this also keeps memory usage down.
  • Schedule heavy jobs off-peak and via real cron instead of triggering them from an admin click, so they're not racing a browser timeout at all.
  • Keep plugins updated. A surprising number of "execution time exceeded" tickets trace back to an old plugin doing an unindexed database query in a loop — the fix isn't a higher timeout, it's a plugin update or a database index.
  • Monitor for the pattern. If the same operation times out every single time regardless of the limit you set, stop raising numbers and profile the query or loop that's actually slow — a timeout is often a symptom of a performance problem, not just a config gap.

Frequently Asked Questions

What's the difference between max_execution_time and memory_limit errors?

max_execution_time is about how long a script runs (in seconds); memory_limit is about how much RAM it can use at once. A script can die from either one independently — a fast script that loads huge datasets hits the memory wall first, while a slow script doing lots of small operations hits the time wall first. The error messages are different too: one says "Allowed memory size exhausted," the other says "Maximum execution time exceeded."

Is it safe to set max_execution_time to 0 (unlimited)?

Not on shared hosting. If a script genuinely hangs — an infinite loop, a stuck API call with no timeout of its own — an unlimited setting means it runs until the process is killed manually or the server runs out of resources, instead of failing after a few minutes. Use a generous but finite number like 300 or 600 seconds instead.

I raised the PHP limit but the import still times out at 60 seconds. Why?

Something else in the chain — Nginx's fastcgi_read_timeout, Apache's Timeout directive, or a CDN/proxy like Cloudflare in front of your site — is enforcing its own, lower limit. PHP's setting only controls PHP; the web server and any proxy in front of it each have their own independent timeout that also needs raising.

Can I just run the import via WP-CLI instead of fixing the timeout?

Yes, and for anything large it's usually the better move. WP-CLI runs from the command line over SSH, isn't subject to the same HTTP request timeout, and skips the browser entirely, so a 20-minute import that would fail in the browser five different ways just runs to completion.

Does raising max_execution_time slow down my whole site?

No. It only affects scripts that actually run that long — a normal page load that finishes in under a second is completely unaffected by whether the ceiling is set to 30 or 300 seconds. The limit is a maximum, not a delay.