Maximum execution time exceeded in WordPress

Een PHP-script liep langer dan de server toestond. Fix het door max_execution_time te verhogen, set_time_limit() aan te roepen of de taak in kleinere stukken te knippen.

Je start een import, een plugin-update of een thumbnail-regeneratie, en WordPress stopt met een blok rode tekst dat er zo uitziet:

Fatal error: Maximum execution time of 30 seconds exceeded in
/home/voorbeeld/public_html/wp-includes/class-wpdb.php on line 2024

Het pad en regelnummer wisselen, maar de vorm is altijd hetzelfde. Een PHP-script draaide langer dan de server toeliet en PHP heeft het afgekapt.

Wat de fout eigenlijk betekent

PHP hanteert per request een wall clock die max_execution_time heet. Zodra dat budget op is, stopt de parser het script, schrijft de fatal naar het error log en valt WordPress halverwege om. De standaardwaarde is in elke PHP web-SAPI 30 seconden. In php-cli is de default 0, en dat is precies waarom dezelfde import via WP-CLI vaak wél lukt terwijl de wp-admin-variant eruit klapt.

Een detail dat vaak over het hoofd wordt gezien: op Linux en macOS telt tijd die doorgebracht wordt in sleep(), databasequeries, bestandsoperaties of HTTP-calls naar externe API's níét mee voor dit budget. Alleen tijd binnen PHP zelf telt. Op Windows is de teller wel realtime en telt alles mee. Die asymmetrie staat in de PHP-handleiding bij set_time_limit() en verklaart waarom een script dat op een Linux-host in deze timeout loopt bijna altijd echt werk staat te doen, en niet gewoon wacht op een trage API.

Meest voorkomende oorzaken, van waarschijnlijk naar zeldzaam

  1. Een importer of exporter die te veel tegelijk verwerkt. WP All Import, WP Import Export Lite, WooCommerce CSV-exports en "regenerate thumbnails"-routines zijn de usual suspects. Die lussen binnen één HTTP-request over duizenden rijen of mediabestanden.
  2. Een backup- of migratieplugin die een volledige archive in de browser bouwt. UpdraftPlus, All-in-One WP Migration, Duplicator en soortgelijke tools kunnen op grotere sites de wall clock raken als je de backup vanuit het dashboard start.
  3. Een trage of hangende externe API-call in een hook. Een verzendkostencalculator, een koersomrekenaar of een analytics-call die 30 seconden blijft hangen binnen een init of template_redirect-hook. Hier speelt de Windows-vs-Linux-nuance van hierboven: op Linux trekt zoiets deze timer alleen als er ondertussen ook echt PHP-werk gebeurt.
  4. Een shared host met de standaard 30 seconden en geen manier om het te overschrijven. Sommige budgethosts hebben set_time_limit() uitgeschakeld én staan geen .htaccess-PHP-overrides toe, waardoor elke langlopende taak gewoon elke keer bij 30 seconden sneuvelt, wat je ook probeert.
  5. Een vastgelopen proces door een infinite loop of recursie-bug in een plugin, thema of eigen functie. Zeldzaam, maar in het error log ziet het er identiek uit.

Bepaal welke oorzaak het bij jou is

Voordat je de limiet omhoog gooit, check je eerst wat er daadwerkelijk te lang loopt. De limiet verhogen op een échte infinite loop betekent alleen dat je site langer blijft hangen voordat hij crasht.

Lees de volledige regel. Het bestandspad in de foutmelding vertelt je welk component er op de stack stond op het moment dat de teller afging. Een pad onder wp-content/plugins/woocommerce-product-importer/ wijst richting de importer. Een pad in wp-includes/class-wpdb.php betekent dat PHP in een databasecall zat op het moment dat het budget op was. Op Linux duidt dat meestal op een trage query binnen een veel grotere loop, niet op een trage database op zich.

Probeer dezelfde actie buiten wp-admin uit te voeren. Start de import via WP-CLI:

wp import producten.csv --user=admin

Verwacht gedrag: WP-CLI gebruikt de php-cli-SAPI waar max_execution_time standaard 0 is. Als dezelfde taak via CLI wél doorloopt, weet je dat het werk zelf klopt en dat het probleem puur de wall clock van de web-SAPI is.

Check je huidige limiet. Zet een klein diagnostiekbestandje in je WordPress-root:

<?php
// phpinfo-check.php, verwijderen na gebruik
echo 'max_execution_time: ' . ini_get('max_execution_time') . PHP_EOL;
echo 'set_time_limit uitgeschakeld: ' . (in_array('set_time_limit', explode(',', ini_get('disable_functions'))) ? 'ja' : 'nee') . PHP_EOL;

Open https://jouwsite.nl/phpinfo-check.php en lees de twee waarden. Wat je bij een standaard host verwacht: max_execution_time: 30 en set_time_limit uitgeschakeld: nee. Staat set_time_limit wel op ja, dan werken methode 2 en 3 hieronder sowieso niet voor jou en moet je bij methode 1 of 4 zijn. Verwijder het bestand nadat je de waarden hebt afgelezen.

Fix 1: limiet verhogen in het hostingpanel

Dit is de enige fix die op elke setup werkt, omdat je de onderliggende php.ini-waarde aanpast die PHP zelf bij het opstarten inleest.

  1. Log in op cPanel en open MultiPHP INI Editor (Plesk: PHP Settings; DirectAdmin: PHP Selector; hPanel: PHP Configuration).
  2. Kies het domein waarvan de WordPress-site deze fout geeft.
  3. Zet het panel in Editor Mode als die optie er is, dan zie je max_execution_time direct als numerieke waarde staan.
  4. Verander 30 in 120. Ga niet meteen naar 600 of hoger. Een heel hoog plafond maskeert echte problemen in plaats van ze op te lossen.
  5. Opslaan. De meeste panels passen de wijziging direct bij het volgende request toe, zonder restart.

Verifieer: open het diagnostiekbestand uit de vorige sectie opnieuw. Je weet dat het werkt als max_execution_time nu 120 weergeeft. Probeer daarna de oorspronkelijke actie opnieuw (de import, update of export). Je weet dat de fix houdt zodra de taak gewoon doorloopt zonder fatal.

Biedt het panel max_execution_time niet aan, of staat de waarde vastgezet? Dan ga je door naar fix 4.

Fix 2: set_time_limit() aanroepen vanuit wp-config.php

Als je de panel-waarde niet kan veranderen, maar je host set_time_limit() niet heeft uitgeschakeld, kun je de limiet in code verhogen. Dat moet in wp-config.php, want dat bestand draait nog vóór WordPress überhaupt een plugin heeft geladen.

  1. Download wp-config.php via SFTP. Bewaar het origineel even als wp-config.php.backup.

  2. Open het in een editor en zoek de regel /* That's all, stop editing! (zie de [wp-config.php-instellingenreferentie](/nl/kennisbank/wordpress/installatie/wp-config-php-instellingen/) voor context) Happy publishing. */.

  3. Zet er direct boven:

    // Geef langlopende imports tot 5 minuten de tijd.
    @set_time_limit( 300 );
  4. Sla het op en upload het bestand terug naar de root van je WordPress-installatie.

De @ onderdrukt een warning voor het geval de host set_time_limit in disable_functions heeft staan. Zonder die @ sloopt die onderdrukte warning je site alsnog.

Eén valkuil die mensen vaak missen: set_time_limit() zet de teller terug naar nul vanaf het moment waarop je hem aanroept, hij telt er niet bij op. Dus als je hem in wp-config.php aanroept, krijgt het hele request een verse 300 seconden vanaf die regel.

Verifieer: open het diagnostiekbestand opnieuw en lees max_execution_time. Dat staat nog steeds op 30 in phpinfo(), omdat je set_time_limit() gebruikt en geen ini_set(). Dat klopt ook. Probeer de oorspronkelijke actie opnieuw. Je weet dat het werkt zodra de taak die eerst bij 30 seconden crashte nu doorloopt.

Verandert er niets? Dan heeft je host set_time_limit() uitgeschakeld, of draai je achter een webservertimeout die er eerder overheen gaat. Ga door naar fix 4.

Fix 3: limiet verhogen via .htaccess (alleen Apache met mod_php)

Dit werkt alleen op Apache met mod_php, en alleen als je host php_value in .htaccess niet heeft dichtgezet. Het werkt niet op nginx, en het werkt ook niet op Apache met PHP-FPM. Combineer dit niet met fix 2.

  1. Download .htaccess uit je WordPress-root. Bewaar het origineel als .htaccess.backup.

  2. Open het en zet deze regel helemaal bovenaan, vóór het # BEGIN WordPress-blok:

    php_value max_execution_time 120
  3. Sla het op en upload het terug.

Verifieer: open de homepage van je site. Je weet dat de directive is geaccepteerd als de pagina gewoon laadt. Je weet dat de host php_value in .htaccess niet ondersteunt zodra je in plaats daarvan een 500 Internal Server Error krijgt. In dat geval haal je de regel die je hebt toegevoegd weer weg, zet je .htaccess.backup terug en gebruik je fix 1 of fix 4.

Check daarna het diagnostiekbestand. max_execution_time zou nu 120 moeten zijn. Probeer de oorspronkelijke actie opnieuw.

Fix 4: vraag je host om de limiet te verhogen

Als niets van bovenstaand blijft hangen, zit je achter een harde limiet die de host afdwingt. Dat zie je vaker bij managed shared hosting en bij budgetplannen met PHP-FPM en dichtgetimmerde pool-configs.

Open een supportticket en geef ze drie concrete dingen mee:

  • De exacte fout, letterlijk uit het log gekopieerd: Fatal error: Maximum execution time of 30 seconds exceeded in /pad/naar/bestand.php on line N.
  • Wat je aan het doen was toen de fout optrad ("WP All Import op een CSV van 40.000 rijen", "volledige UpdraftPlus-backup gestart", "thumbnails regenereren op 8.000 afbeeldingen").
  • Een duidelijke vraag: "Zet max_execution_time voor mijn account op 300, of bevestig dat mijn pakket de 30 seconden niet kan overschrijden en leg uit welk pakket dat wel toestaat."

Een goede host antwoordt in één bericht. Een slechte host laat je van het kastje naar de muur lopen. Hoe dan ook heb je nu zwart-op-wit wat het plafond is, en dat is weer bruikbare informatie voor de beslissing of je de taak misschien helemaal van het webrequest af moet trekken (zie de preventie-sectie hieronder).

Wanneer je moet escaleren

Als je fix 1 en fix 4 hebt geprobeerd en de taak blijft timeouten, verzamel dan dit voordat je iemand om verdere hulp vraagt. Dit is precies wat een ontwikkelaar of support op de tweede mail toch al aan je gaat vragen:

  • De volledige regel uit het PHP error log, inclusief bestandspad en regelnummer.
  • De output van het diagnostiekbestand met max_execution_time en de status van set_time_limit.
  • Je WordPress-versie (Dashboard: Updates), PHP-versie (Gereedschap: Sitediagnose: Info: Server) en de naam van je hostingpakket.
  • De lijst met plugins die actief zijn op het moment dat de fout afgaat, met name degene die de langlopende actie triggert.
  • Of dezelfde actie via WP-CLI wél doorloopt. Dat ene gegeven vertelt iedereen die meeleest of het probleem het werk is of de wall clock.
  • Eventuele regels uit wp-content/debug.log van de minuut vóór de fatal.

Als de taak iets terugkerends is (een nachtelijke import, een wekelijks WooCommerce-rapport, een backup), escaleer dan vóór de volgende run. Dat soort taken hoort sowieso niet op de web-SAPI thuis, en een host die zijn geld waard is helpt je die te verhuizen naar een cron-gedreven WP-CLI-command of een fatsoenlijke background queue.

Voorkom dat de fout terugkomt

De limiet omhoog zetten is een prima fix voor een eenmalige taak. Het is geen strategie voor iets wat steeds terugkomt. Met deze drie gewoontes zie je deze fout nog maar zelden:

  • Batch elke import of export. WP All Import heeft records_per_iteration. De ingebouwde WooCommerce-importer streamt rijen. Eigen scripts moeten per 100 tot 500 rijen werken, niet 40.000 in één keer. Een gebatchte import herstelt bovendien netjes van een timeout, omdat elke batch op zichzelf staat.
  • Haal langlopende taken van het webrequest af. Backups, thumbnail-regeneraties en grote imports horen achter WP-CLI of een cronjob, niet achter een dashboardknop. max_execution_time op php-cli is 0, dus de wall clock verdwijnt helemaal. Als je de server niet zelf beheert, kan een managed host dit voor je regelen.
  • Geef trage externe API-calls een eigen timeout. Een hangende externe call geeft op Linux meestal niet direct deze specifieke fout (zie de nuance van eerder), maar hij houdt wel een PHP-worker bezet tot het request alsnog sneuvelt. Zie je deze fout samen met symptomen als trage front-end-pagina's, lees dan het artikel over PHP workers exhausted in WordPress om te begrijpen wat er ondertussen met de rest van je site gebeurt.

Lost het verhogen van max_execution_time de melding op, maar zie je in dezelfde workflow óók "allowed memory size"-fouten? Dan kijk je waarschijnlijk naar twee kanten van dezelfde runaway taak. Het gerelateerde artikel over allowed memory size exhausted behandelt de geheugenkant van hetzelfde verhaal. En als het script halverwege klapt en je site een fatal aan bezoekers laat zien, legt het artikel over de kritieke fout op deze website uit hoe WordPress dat richting de front-end laat zien en hoe je de site weer online krijgt.

Klaar met terugkerende traagheid?

Traagheid komt vaak terug na snelle fixes. Professioneel onderhoud houdt updates, caching en limieten consequent op orde.

Bekijk WordPress onderhoud

Doorzoek deze site

Begin met typen om te zoeken, of blader door de kennisbank en blog.