← Terug naar kennisbank HOSTING

504 Gateway Timeout — wat het betekent en hoe je 'm oplost

Bezoekers wachten 30 of 100 seconden, krijgen dan "504 Gateway Timeout". Anders dan een 502 (waar de backend ongeldig antwoordde) reageerde je backend hier helemaal niet op tijd. Verleidelijke reflex: timeouts verhogen. Maar in 90% van de gevallen lost dat het echte probleem niet op — het verstopt 't alleen. Deze gids legt uit wat een 504 wél en niet betekent en hoe je de echte oorzaak vindt.

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_timeout 60 seconden, proxy_read_timeout 60 seconden
  • PHP max_execution_time: standaard 30 seconden
  • Apache: Timeout standaard 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 secondenmax_execution_time in 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-FPM
  • fastcgi: upstream timed out — idem
  • request timed out — Apache wachtte op script
  • PHP 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_options autoload 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_children in 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.php in een echte cron-job, niet via wget jouwsite.nl/cron.php
  • Tasks splitsen in batches — verwerk 100 records per run, gepland elke 5 minuten
  • WP Cron problemen: schakel DISABLE_WP_CRON in en stel een echte server-cron in op wp-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.

Vuistregel: als een pagina >3 seconden duurt, knijpen je gebruikers al af; als 'ie >30 seconden duurt is er fundamenteel iets mis. Het echte werk is altijd: waaróm duurt deze request zo lang? Pas als je dat hebt opgelost is timeout-verhoging optioneel.

Diagnose-stappenplan

  1. Tijd hoe lang het duurt voor 504 verschijnt — welke timeout slaat?
  2. Op welke pagina/actie consistent? (Geeft hint over oorzaak — admin, checkout, archive, custom URL)
  3. Open server error_log. Zoek naar upstream timed out of Maximum execution time
  4. Schakel slow query log in MySQL aan, kijk wat na een dag bovenaan staat
  5. Deactiveer recent geïnstalleerde plugins één voor één — vaak is een plugin-API-call de bottleneck
  6. Check externe afhankelijkheden: payment gateways, mail services, productfeed-leveranciers — wisselen ze recent traag?
  7. Op piek-momenten? Mogelijk PHP-FPM-saturatie — workers verhogen of caching aanzetten
  8. Lange cron-tasks? Verplaatsen naar CLI, splitsen in batches
  9. 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.