De foutmelding kent enkele schrijfwijzen, allemaal zelfde betekenis:
- 504 Gateway Timeout
- 504 Gateway Time-out
- HTTP Error 504
- Error 504 Cloudflare (oranje pagina met Ray ID)
- 504 ERROR — The request could not be satisfied
- "The server was acting as a gateway and did not receive a response in time"
- Nginx-default: "504 Gateway Time-out" in plain tekst
Wat betekent een 504 precies?
Net als bij 502 gaat 't om een keten:
Bezoeker → Cloudflare → Hosting Nginx → PHP-FPM → MySQL/externe API
Bij een 504 is het verschil dat ergens in die keten een component zit te wachten op een response die niet binnen de timeout komt. De wachtende partij geeft 't op en stuurt 504 terug naar de bezoeker.
Belangrijke timeouts om te kennen:
- Cloudflare: 100 seconden harde limiet voor het Free-plan. Pro/Business iets meer, Enterprise instelbaar tot 6000s. Niet aanpasbaar op Free.
- Nginx: standaard
fastcgi_read_timeout60 seconden,proxy_read_timeout60 seconden - PHP
max_execution_time: standaard 30 seconden - Apache:
Timeoutstandaard 60 seconden - Browser: meestal 5-10 minuten, dus zelden de boosdoener
De kortste timeout in de keten "wint" — als Cloudflare na 100 seconden afkapt maar PHP nog 60 seconden bezig is, dan ziet jouw bezoeker 504 terwijl PHP-server vrolijk doorrekent (en uiteindelijk z'n werk afmaakt zonder dat iemand dat merkt).
Onderscheid met andere fouten
- 500 — applicatie crashte met fatal. Zie 500 Internal Server Error oplossen
- 502 — backend antwoordde wel, maar het antwoord was ongeldig of de connectie brak af. Zie 502 Bad Gateway oplossen
- 503 — service tijdelijk niet beschikbaar (vaak onderhoud, soms overload-protectie)
- 504 — backend antwoordde überhaupt niet binnen de tijd
Stap 1: lokaliseer welke timeout het is
Tijd hoe lang het duurt voordat de 504 verschijnt:
- ~30 seconden —
max_execution_timein PHP - ~60 seconden — Apache Timeout of Nginx default
fastcgi_read_timeout - ~100 seconden — Cloudflare Free-plan harde limiet
- ~300 seconden — Nginx of hosting custom config
- Onregelmatig — verschillende oorzaak per request
Het tijdstip vertelt je vaak meteen welke laag het is. Een consistent 100-seconden-504 met Cloudflare = vrijwel zeker Cloudflare's limiet.
Stap 2: lees server error_log
Andere meldingen dan bij een 502:
upstream timed out (110: Connection timed out)— Nginx wachtte tevergeefs op PHP-FPMfastcgi: upstream timed out— idemrequest timed out— Apache wachtte op scriptPHP Fatal error: Maximum execution time of 30 seconds exceeded— PHP zelf gaf op
Specifiek bij Maximum execution time: de exacte regel waar PHP afbrak staat ook in het log. Daar zit je trage code.
De vijf meest voorkomende oorzaken
1. Trage database-query
Verreweg de meest voorkomende oorzaak. Een query op een grote tabel zonder index, een join over miljoenen rijen, of een query die alle posts laadt zonder paginatie. Symptoom: 504 alleen op specifieke pagina's (vaak admin-pagina's, archive-views, of catalog-filters).
Diagnose: zet MySQL slow query log aan (vraag hosting-support om dat te doen, of via SSH zelf). Wacht een dag, kijk welke queries >5 seconden duren — die zijn je 504-veroorzakers.
Fix:
- Indexen toevoegen op kolommen die in WHERE/JOIN/ORDER BY voorkomen
- Database optimaliseren: bij WordPress
wp_optionsautoload trimmen, post revisions opruimen - Cachen van dure pagina's zodat ze niet elke keer opnieuw uitgerekend hoeven te worden
- Bij WooCommerce: oude order-data archiveren, transient cleanup
2. Externe API-call die hangt
Site doet een call naar een externe service (mailprovider, payment, koppeling met boekhoudsoftware, externe productfeed) en die service reageert traag of niet. Jouw site blokkeert tot de timeout slaat.
Diagnose: error_log kijken voor cURL-meldingen of socket-timeouts. Of de plugin in kwestie tijdelijk uitschakelen om te zien of 504 wegblijft.
Fix:
- Korte timeouts op externe calls in code:
curl_setopt($ch, CURLOPT_TIMEOUT, 5); - Async-verwerking via WordPress' Action Scheduler of een queue-plugin — niet wachten op externe call binnen pageload
- Cache externe data: een productfeed van een leverancier 1x per uur ophalen, niet bij elk pageload
- Failover-logica: als externe API niet reageert, valt site terug op cached versie
3. PHP-FPM workers allemaal bezet
Net als bij 502: alle workers druk met andere requests. Bij 504 is het symptoom: nieuwe requests staan in de queue te wachten, en de wachttijd overschrijdt de proxy-timeout.
Diagnose: PHP-FPM-status-pagina (als hosting die heeft), of CPU/load monitoring. Op piek-momenten consistent 504 = saturatie waarschijnlijk.
Fix:
- Verhoog
pm.max_childrenin PHP-FPM-config (via hoster vragen) - Onderzoek wáárom requests zo lang duren — meestal queries of externe calls (zie 1 en 2 hierboven)
- Caching activeren — een gecachte pagina kost 1 worker voor 50ms in plaats van 5 seconden
- Zwaarder hosting-pakket overwegen als shared te krap is
4. Lange cron-jobs of import-scripts blokkeren
Een dagelijkse cron-job (productfeed-import, mail-zending naar grote lijst) draait in PHP-FPM en houdt een worker uren bezet. Tijdens die periode merken bezoekers 504's.
Fix:
- Lange tasks via CLI draaien, niet via web-cron:
php /path/script.phpin een echte cron-job, niet viawget jouwsite.nl/cron.php - Tasks splitsen in batches — verwerk 100 records per run, gepland elke 5 minuten
- WP Cron problemen: schakel
DISABLE_WP_CRONin en stel een echte server-cron in opwp-cron.php
5. Cloudflare 100-seconden-limiet
Op Cloudflare Free: requests die langer dan 100 seconden duren krijgen automatisch 524 (timeout) of 504, afhankelijk van waar de timeout valt. Dat is een hard limit en niet te verhogen op Free.
Fix:
- Code optimaliseren zodat 't sneller dan 100 seconden klaar is
- Cloudflare uitzetten op specifieke endpoints: voor lange-actie URL's (cron, webhook-handlers, exports) een DNS-record met grijze wolk (DNS only, geen proxy)
- Lange tasks async maken — direct response naar bezoeker, taak op de achtergrond
- Cloudflare Pro/Business voor hoger limiet, of Enterprise voor configurable
Specifieke scenario's
504 alleen op bestelpagina (WooCommerce)
Klassiek: betaalprovider (Mollie, Stripe, iDeal) reageert traag, en je checkout wacht erop. Of een e-mail-plugin probeert direct mail te sturen tijdens de order-flow. Fix: betaalcalls async, mail naar een queue, transients voor product-data.
504 alleen op /wp-admin/
Admin-pagina's met veel filters of bulk-acties op grote datasets. WordPress dashboard met "Recent Activity"-widget die alle posts indexeert. Fix: zwaarder hosting-pakket, plugins die admin-snelheid optimaliseren, of dashboard-widgets uitschakelen.
504 op import van een .csv of grote upload
Te grote import in één request. Fix: gebruik plugins/tools die importeren in batches (WP All Import, Better Search Replace via WP-CLI). Of upload via SSH.
504 sinds Cloudflare-activatie
Origin-server is op zich snel, maar specifieke admin- of webhook-paden zijn langzaam. Voor hen Cloudflare uitschakelen via DNS-record met grijze wolk (alleen DNS, geen proxy). Of een Page Rule met "Bypass Cache" maken.
De verleidelijke fix: timeouts verhogen
Bijna iedere oudere blog-post over 504 zegt: "verhoog je timeouts!" Dat is technisch correct als noodfix, maar zelden de echte oplossing.
// PHP max_execution_time
@ini_set('max_execution_time', 300);
// In .htaccess
php_value max_execution_time 300
// Of in .user.ini
max_execution_time = 300
Wat dit doet: PHP mag nu 5 minuten doen over wat eerst in 30 seconden moest. Resultaat:
- Bezoekers wachten nu 5 minuten in plaats van 30 seconden voor ze de 504 krijgen — zelfde uitkomst
- Of, als 't toevallig binnen die tijd lukt: pagina laadt in 2 minuten — gebruikerservaring nog steeds slecht
- PHP-FPM-workers blijven langer bezet → minder workers beschikbaar → 504's verschuiven naar andere requests
Verhogen is een tijdelijke buffer, niet een oplossing. Het probleem is dat je code te lang doet over een actie. Daar zit de fix.
Diagnose-stappenplan
- Tijd hoe lang het duurt voor 504 verschijnt — welke timeout slaat?
- Op welke pagina/actie consistent? (Geeft hint over oorzaak — admin, checkout, archive, custom URL)
- Open server error_log. Zoek naar
upstream timed outofMaximum execution time - Schakel slow query log in MySQL aan, kijk wat na een dag bovenaan staat
- Deactiveer recent geïnstalleerde plugins één voor één — vaak is een plugin-API-call de bottleneck
- Check externe afhankelijkheden: payment gateways, mail services, productfeed-leveranciers — wisselen ze recent traag?
- Op piek-momenten? Mogelijk PHP-FPM-saturatie — workers verhogen of caching aanzetten
- Lange cron-tasks? Verplaatsen naar CLI, splitsen in batches
- Cloudflare aan? Check of het de 100s-limiet is
Wanneer schakel je hulp in?
- 504's komen consistent voor en je weet niet welke trage operatie de oorzaak is
- Slow query log wijst naar query's die je niet zonder downtime kunt aanpassen (productieshop)
- Externe API-calls hangen, je hebt geen controle over de externe partij, en code moet async
- WooCommerce-shop, betaalpagina geeft 504 → orders gaan verloren elke minuut
- Cloudflare 100s-limiet is een hard probleem voor je import/cron-flow
- Je hebt timeouts al verhoogd en het probleem blijft bestaan — wijst op resource-uitputting of code-issue dat je niet zonder hulp vindt
Een 504 is bijna altijd een teken dat ergens iets te lang duurt — niet dat de timeout te kort is. De juiste vraag is daarom: "wat duurt te lang en waarom?" Vaak is dat één query, één externe call of één plugin. Met de juiste tools (slow query log, error_log, profiler) vind je die in een halfuur. Daarna is de fix meestal klein. Wat veel tijd kost is het zonder ervaring vinden.