Je WordPress-site (of een specifiek endpoint) geeft HTTP 429 terug, met een body die "Too Many Requests" zegt. Je ziet het in de browser, in het HTTP API Calls-paneel van Query Monitor, in wp-content/debug.log of in je nginx access log. Soms geeft één pagina een 429. Soms zien alleen ingelogde beheerders het. Soms is het alleen zichtbaar als een mislukt uitgaand verzoek naar woocommerce.com of een andere externe API. Soms verdwijnt het vanzelf na 10 minuten en komt het een uur later weer terug.
Wat een 429 echt betekent
RFC 6585 §4 definieert 429 als: "The 429 status code indicates that the user has sent too many requests in a given amount of time ('rate limiting')." De spec is bewust kort. Er staat niet wie die gebruiker is, welke limiet het was of wanneer je het opnieuw mag proberen. Er staat alleen dat ergens in de keten iets verzoeken van iemand heeft geteld en besloten heeft even niet meer te antwoorden.
Drie details uit RFC 6585 zijn belangrijk voor je diagnose:
Retry-Afteris optioneel. Het antwoord "MAY include a Retry-After header indicating how long to wait". Geen SHOULD, geen MUST. Je mag er dus niet vanuit gaan dat elke 429 een retry-hint bevat, en als die van jou er geen heeft is dat gewoon spec-conform.- De body SHOULD de conditie uitleggen. De RFC beveelt aan (maar eist niet) dat de body vertelt wat de limiet was. In de praktijk geven generieke "429 Too Many Requests"-pagina's je niks nuttigs en moet je naar de logs.
- 429-antwoorden MUST NOT worden gecachet. Zie je een 429 die voor één bezoeker over meerdere browsers aanhoudt en nooit verdwijnt, dan is het geen stale CDN-cache maar een actieve rule.
Die definitie is belangrijk omdat hij je vertelt wat een 429 niet is. Een 429 is geen crash. Geen DDoS-symptoom. Geen "server is traag". Het is een bewuste, gezonde weigering. Wie de 429 stuurde had genoeg capaciteit over om het verzoek te parsen, te tellen en beleefd te antwoorden. Het werk van diagnose is uitzoeken welke laag nee zei, en of het verkeer dat geteld werd afkomstig was van je bezoekers, je eigen cron of een integratie die naar buiten belt vanuit je site.
Een 429 is niet hetzelfde als de andere overbelasting-gerelateerde fouten in deze categorie, en dat onderscheid is belangrijk:
- 429 Too Many Requests: er is een rate limit afgegaan. Bewust, gericht en meestal op één bron gericht. Hierover gaat dit artikel.
- 503 Service Unavailable: de server zelf is overbelast of staat in onderhoud. Ongericht, iedereen heeft er last van. Let op: een verkeerd geconfigureerde nginx
limit_req-rule geeft standaard een 503 terug in plaats van een 429, dus een deel van "jouw 429's" kan eigenlijk als 503 langskomen. - 504 Gateway Timeout: de upstream was bereikbaar maar deed er te lang over. Heeft niks met rate limits te maken.
- 500 Internal Server Error: de applicatie zelf heeft een fout gegooid.
Veelvoorkomende oorzaken, op volgorde van waarschijnlijkheid
Het lastige aan een WordPress-429 is dat vijf verschillende lagen er eentje kunnen produceren, en ze zien er vanuit de browser grofweg hetzelfde uit. Hier staan ze in de volgorde waarin ik ze in de praktijk tegenkom.
1. Je site rate-limit zichzelf via eigen uitgaande API-calls
Dit is de meest voorkomende WordPress-429 in 2026 en bijna niemand verwacht het. Het mechanisme is simpel en zelf-veroorzaakt:
- Een plugin schedulet een terugkerende achtergrondtaak (via Action Scheduler of
wp_schedule_event). - De taak doet een uitgaand HTTP-verzoek naar een externe API.
- De externe API rate-limit per uitgaand IP.
- Je job faalt, Action Scheduler probeert het opnieuw met exponentiële backoff.
- Op shared of managed hosts die een gedeeld NAT-uitgaand IP gebruiken, bellen andere sites op hetzelfde IP ook naar dezelfde API, en het gecombineerde verkeer trapt de externe rate limit af.
- Je error log vult zich met 429's voor een URL die je bezoekers nooit zelf aanraken.
Het leerboekvoorbeeld is het WooCommerce.com Helper-endpoint op https://woocommerce.com/wp-json/helper/1.0/update-check, dat je betaalde WooCommerce-extensies controleert op updates en licentie-geldigheid. Er is een gedocumenteerde casus op het WordPress.org supportforum waarin een Cloudways-klant continu 429's kreeg op precies die URL. De oorzaak: Google Listings & Ads-jobs in Action Scheduler die steeds opnieuw retryden, elke retry triggerde een licentiecheck, en de rate limit van WooCommerce.com op het gedeelde Cloudways-uitgaand IP bleef ze weigeren. De 429 kwam dus niet van Cloudways, niet van Cloudflare, niet van de origin en niet van een aanvaller. Het was WooCommerce.com die keurig een uitgaand IP rate-limitede dat te vaak bij ze aanklopte.
Hetzelfde patroon zie je bij Google-API's (Google Listings & Ads, Google Analytics-plugin-integraties), Mailchimp-sync-plugins, automatic.css-licentiechecks en elke plugin die volgens een schema een externe dienst pollt. Zie je 429-meldingen in de PHP error log of in Query Monitor's HTTP API-tab, en wijst de URL naar een externe domeinnaam, dan zit je vrijwel zeker in deze oorzaak.
2. Een rate limit voor wp-login.php doet zijn werk
Rate-limiting op login-POSTs is verwacht gedrag en de 429 is hier meestal correct. Wordfence throttlet verzoeken per IP standaard, All In One Security heeft een vergelijkbare login-lockout, en veel managed hosts voegen hun eigen nginx limit_req-rule toe op /wp-login.php die na een instelbare burst een 429 teruggeeft. Zit je 429 beperkt tot /wp-login.php (of /xmlrpc.php, wat hetzelfde aanvalsoppervlak is), dan gaat de limiet bewust af en moet je hem met rust laten, tenzij hij echte gebruikers buitensluit. Zodra hij een echte gebruiker tegenhoudt deban je het IP en laat je de rule staan.
De typische misconfiguratie hier: nginx rate limits die een 503 teruggeven in plaats van een 429. De limit_req-module van nginx staat standaard op limit_req_status 503, dus veel 503's die op een login-URL lijken af te gaan zijn eigenlijk een login-rate-limit met de verkeerde statuscode. limit_req_status 503 in limit_req_status 429 veranderen in het server-block is de juiste fix, want 429 is de semantisch correcte status voor "je doet te veel verzoeken".
3. De WordPress Heartbeat API of wp-cron raakt een origin-rate-limit
De Heartbeat API stuurt POSTs naar /wp-admin/admin-ajax.php elke 15 seconden op bewerk-pagina's en elke 60 seconden op het dashboard. Die verzoeken gaan om de pagecache heen omdat het POSTs zijn. Op shared hosts met een harde per-account requests-per-seconde-cap kunnen 5 gelijktijdige beheerders genoeg admin-ajax-verkeer genereren om de eigen 429 van de host te triggeren. Iets vergelijkbaars geldt voor WP-Cron: die firet standaard op elke pagelaad, en een site met gelijktijdig verkeer en een lange wachtrij kan wp-cron.php vaak genoeg raken om een server-level cap te laten afgaan.
Allebei op te lossen, maar wel verschillend: de Heartbeat vertraag je (via het heartbeat_settings-filter of een optimalisatie-plugin) en de pseudo-cron vervang je door een echte servercron. Die laatste helft beschrijf ik uitgebreid in mijn artikel over WP-Cron dat niet werkt.
4. Cloudflare (of een andere CDN-edge) past een rate-limiting-regel toe
Cloudflare rate-limit WordPress-sites niet standaard. Een 429 van Cloudflare betekent dat iemand (waarschijnlijk jij, of een security-gids die je hebt gevolgd) een Cloudflare rate limiting rule in het dashboard heeft aangemaakt en dat die afgaat. Gangbare gevallen: een /wp-json/*-rule die te strak stond voor je eigen REST-integraties, een /wp-login.php-rule die je monitor blokkeert, of een site-brede rule die uit een blogpost is overgenomen zonder de drempel aan te passen.
Cloudflare-429's zien er in de browser identiek uit aan origin-429's. De enige betrouwbare manier om ze uit elkaar te houden is het Cloudflare-analytics-dashboard (Security > Events, gefilterd op "Action: block" en "Service: Rate limiting") of de server-access-log. De aanwezigheid van een CF-Ray-header in de response zegt niks over de bron. CF-Ray wordt aan elke Cloudflare-proxied response toegevoegd, of de 429 nou van Cloudflare kwam of van de origin erachter.
5. De WAF van de host of een securityplugin geeft een 429 uit eigen regels
Wordfence throttlet generieke verzoeken standaard op 240 per minuut per IP en crawlers op 120 pageviews per minuut. WP Engine en SiteGround publiceren hun drempels niet maar geven een 429 terug zodra je "het maximale aantal verzoeken naar een pagina in de laatste seconde" overschrijdt. WordPress VIP publiceert wel expliciete getallen: 10 requests per seconde voor crawlers aan de edge, 10 XML-RPC-verzoeken per 30 seconden per IP, en 5 mislukte logins per 5 minuten. Komt je 429 van zo'n platform en correleert hij met een specifiek IP of gedragspatroon, dan doet de host exact waar je voor betaalt en is de fix ofwel dat IP op een allowlist zetten, ofwel de caller rustiger laten bellen.
Eén bijzonder geval: gaat de 429 alleen af op /wp-json/wc/store/*-endpoints op een WooCommerce-site, controleer dan of WooCommerce Store API rate limiting in je configuratie is aangezet. Dat is geïntroduceerd in WooCommerce 7.2 (december 2022), staat standaard uit en kan aangezet worden via het woocommerce_store_api_rate_limit_options-filter. Als het aanstaat is de standaarddrempel 25 POST-verzoeken per 10 seconden per IP, en het antwoord bevat RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset en RateLimit-Retry-After-headers zodat je de exacte limiet in de network-tab van je browser kunt zien.
Onderzoek welke oorzaak van toepassing is
Deze checks zijn niet-destructief. Loop ze in volgorde af voordat je iets verandert.
Check 1: bepaal of de 429 inkomend of uitgaand is.
Zie je de 429 in je browser als je naar de site gaat, dan is hij inkomend (oorzaken 2 tot en met 5). Zie je hem in wp-content/debug.log, in de HTTP API Calls-tab van Query Monitor of in een foutmelding van een plugin, en wijst de URL naar een extern domein zoals woocommerce.com of googleapis.com, dan is hij uitgaand (oorzaak 1).
Om uitgaande 429's zichtbaar te maken in de logs, zet je tijdelijk WordPress debug logging aan in wp-config.php:
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
Reproduceer daarna de fout of wacht erop en lees wp-content/debug.log. Een uitgaande 429 ziet er in de log van Action Scheduler zo uit:
action failed: WP_Error Object ( [errors] => Array (
[http_429] => Array ( [0] => You are being rate limited. )
) )
Je weet dat het gelukt is wanneer je met zekerheid kunt zeggen of de 429 een antwoord is dat je bezoekers van jouw site krijgen, of een antwoord dat jouw site van iemand anders server krijgt. Dat zijn echt twee verschillende problemen.
Zet WP_DEBUG daarna weer op false, anders lekken debug-berichten in productie.
Check 2: lees de access log (voor inkomende 429's).
Open de access-log-viewer in je hostingpaneel (cPanel: Metrics > Raw Access, Plesk: Logs, of het equivalent bij jouw provider) en zoek naar regels met statuscode 429. Waar je naar zoekt is de request-URL die de 429 veroorzaakt. Let op welke URL het vaakst voorkomt.
Heb je SSH-toegang:
grep ' 429 ' /var/log/nginx/access.log \
| awk '{print $7}' \
| sort \
| uniq -c \
| sort -rn \
| head -20
Of je nu het paneel of de commandline gebruikt, de meest voorkomende URL wijst je naar de volgende stap. Is de top-URL /wp-login.php, dan zit je in oorzaak 2 (login-rate-limit). Is het /wp-admin/admin-ajax.php, dan zit je in oorzaak 3 (Heartbeat). Is het /wp-cron.php, dan zit je in oorzaak 3 (WP-Cron). Is het /wp-json/wc/store/* op een WooCommerce-site, dan zit je waarschijnlijk in oorzaak 5 (Store API rate limiting aangezet). Is het een generieke frontend-URL die door één specifiek IP wordt geraakt, dan zit je in oorzaak 2 of 4 (een rate-limit-regel die tegen een echte client afgaat).
Je weet dat het gelukt is wanneer je de exacte request-URI en het client-IP van de 429 hebt, en je hebt beslist of de limiet je tegen iets echts beschermt of je uit je eigen site sluit.
Check 3: houd Cloudflare en origin uit elkaar (voor Cloudflare-proxied sites).
Vertrouw niet op de CF-Ray-responseheader om te beslissen of Cloudflare of je origin de 429 gaf. Die header staat op elke Cloudflare-proxied response en kan je niet vertellen welke laag de statuscode genereerde. Gebruik in plaats daarvan het Cloudflare-dashboard: Security > Events, filter op "Action: block" en "Service: Rate limiting". Een door Cloudflare geblokkeerde 429 verschijnt daar met de naam van de specifieke regel. Laat de Events-pagina geen matchende rate-limit-event zien voor het tijdstip van de fout, dan heeft Cloudflare de 429 niet gegenereerd en kwam hij van de origin.
Of omzeil Cloudflare helemaal met curl --resolve:
curl --resolve jouwsite.nl:443:1.2.3.4 -I https://jouwsite.nl/de-falende-url/
Vervang 1.2.3.4 door je echte origin-IP. Geeft het directe verzoek naar de origin een 200 en geeft het verzoek via Cloudflare een 429, dan komt de 429 van Cloudflare en zit de fix in het Cloudflare-dashboard. Geven ze allebei een 429, dan komt hij van je origin en laat Cloudflare hem alleen maar doorlopen.
Je weet dat het gelukt is wanneer je kunt zeggen "Cloudflare-rule X gaat af" of "de origin zelf geeft een 429 terug". Alles vager dan dat is gokken.
Check 4: zoek op hol geslagen Action Scheduler-jobs (voor uitgaande 429's).
In de WordPress-admin ga je naar Tools > Scheduled Actions (dit is de UI van Action Scheduler, aanwezig als WooCommerce of een andere plugin die Action Scheduler gebruikt geïnstalleerd staat). Filter op status "Failed" en sorteer op datum. Een site met een op hol geslagen uitgaande taak laat tientallen tot honderden mislukte acties zien met dezelfde hooknaam, elk falend binnen minuten van de vorige retry. De hooknaam vertelt je welke plugin de dader is: gla/jobs/update_products is Google Listings & Ads, wc_helper_subscriptions_refresh is de WooCommerce.com Helper, enzovoort.
Voor een diepere blik:
wp action-scheduler list --status=failed --per-page=50
Je weet dat het gelukt is wanneer je de exacte plugin en de exacte hook kunt noemen die het uitgaande verzoek honderden keren aan het retryen is.
Oplossingen, per oorzaak
Fix voor oorzaak 1: je site slaat een externe API plat
Dit is de meest voorkomende oorzaak en de meest bevredigende om op te lossen, omdat de 429 verdwijnt zodra je stopt met het zelf veroorzaakte verkeer.
-
Identificeer de op hol geslagen plugin. Gebruik Check 4 hierboven om de hooknaam met het hoogste aantal gefaalde jobs te vinden.
-
Schakel de plugin (of de specifieke feature) tijdelijk uit om te bevestigen dat zij de bron is. Het aantal gefaalde acties in Scheduled Actions moet binnen 15 minuten stoppen met oplopen.
-
Verwijder de backlog van gefaalde acties zodat Action Scheduler stopt met retryen. In de WordPress-admin: Tools > Scheduled Actions, filter "Failed", bulk selecteren, verwijderen. Of via WP-CLI:
wp action-scheduler clean --status=failed -
Zet de pseudo-cron van WP-Cron uit en vervang hem door een echte servercron, zodat jobs op een schema lopen dat jij bepaalt in plaats van op elke pageview. Open
wp-config.phpvia de bestandsbeheerder in je hostingpaneel (of download het bestand via SFTP) en voeg deze regel toe boven het "That's all, stop editing!"-commentaar:define( 'DISABLE_WP_CRON', true );Stel vervolgens een cronjob in die elke 15 minuten
wp-cron.phpaanroept. In de meeste hostingpanelen (cPanel: Cron Jobs, Plesk: Geplande taken) maak je een nieuwe cron aan met het schema*/15 * * * *en het commando:wget -q -O - "https://jouwsite.nl/wp-cron.php?doing_wp_cron" >/dev/null 2>&1WP-CLI-alternatief (als je SSH-toegang hebt): het WP-CLI-equivalent is netter omdat het helemaal niet langs de webstack gaat:
*/15 * * * * cd /var/www/jouwsite.nl && wp cron event run --due-now >/dev/null 2>&1De volledige onderbouwing van die switch staat in mijn artikel over WP-Cron dat niet werkt.
-
Zet de plugin weer aan en hou het in de gaten. Komen de 429's terug, dan probeert de onderliggende integratie echt meer verkeer te pushen dan de externe API toestaat, en zit de fix aan de pluginkant (minder pollen, requests bundelen) of aan de hostingkant (overstappen naar een host met een dedicated uitgaand IP, zodat je de externe rate limit niet meer deelt met vreemden).
Je weet dat het gelukt is wanneer het aantal "Failed"-acties in Scheduled Actions niet meer oploopt, de PHP error log geen uitgaande 429-entries meer bevat en de integratie ook echt weer werkt (producten syncen, licenties verversen, stats updaten).
Fix voor oorzaak 2: een login-rate-limit gaat af
Zit de 429 op /wp-login.php en hoort het bron-IP bij een brute-force-aanvaller, laat het dan met rust. De rate limit is correct, 429 is het juiste antwoord en de aanvaller unbannen zou je site onveiliger maken.
Sluit de 429 een echte gebruiker buiten (jezelf, je klant, je monitor):
-
In Wordfence: ga naar Wordfence > Tools > Live Traffic om het geblokkeerde verzoek te zien, dan Wordfence > Firewall > Blocking om het block te verwijderen. Om herhaling te voorkomen voeg je het IP toe aan Wordfence's Whitelisted Services of stel je Rate Limiting in op Wordfence > Firewall > All Firewall Options > Rate Limiting met een minder agressieve drempel.
-
Heb je SSH-toegang en zit de rate limit in een nginx
limit_req-rule: pas het server-block aan om de rate of burst te verhogen, en zorg dat de statuscode 429 is en geen 503:limit_req_zone $binary_remote_addr zone=wp_login:10m rate=5r/m; location = /wp-login.php { limit_req zone=wp_login burst=10 nodelay; limit_req_status 429; # ... rest van de location ... }rate=5r/mstaat 5 verzoeken per minuut per IP toe,burst=10zet tot 10 extra verzoeken zonder vertraging in de wachtrij enlimit_req_status 429zorgt dat de juiste statuscode terugkomt in plaats van de standaard 503. -
Bij een managed host (WP Engine, Kinsta, Cloudways, SiteGround): de regel zit niet onder jouw beheer. Open een supportticket met het exacte bron-IP, de timestamp en de URL, en vraag ze het IP op de allowlist te zetten.
Je weet dat het gelukt is wanneer het IP dat werd buitengesloten zonder throttling weer kan inloggen (of de doel-URL kan raken) en aanvallers nog steeds worden geblokkeerd. Test beide.
Fix voor oorzaak 3: Heartbeat of WP-Cron raakt een rate limit van de host
Heartbeat is het waard om te vertragen, niet om te killen. Heartbeat helemaal uitzetten breekt autosave en post locking, wat een groter probleem is dan de 429.
De makkelijkste manier om het te vertragen is via een performanceplugin die je gewoon in wp-admin configureert. Perfmatters, WP Rocket en LiteSpeed Cache hebben allemaal een Heartbeat-control-sectie waar je het interval van 15 seconden naar 60 seconden kunt verhogen, of Heartbeat specifiek op de frontend kunt uitzetten (wat veilig is, want frontend Heartbeat wordt maar door een handvol plugins gebruikt).
Liever via code: verleng het interval via het heartbeat_settings-filter in een klein mu-plugin of codesnippet:
add_filter( 'heartbeat_settings', function ( $settings ) {
$settings['interval'] = 60; // seconden, omhoog van de standaard 15 op bewerk-pagina's
return $settings;
} );
Voor WP-Cron pas je de fix uit Oorzaak 1, stap 4 toe: definieer DISABLE_WP_CRON en voeg een echte servercron toe. Dat cap de cron-rate op een schema dat jij bepaalt.
Je weet dat het gelukt is wanneer de nginx-access-log een scherpe daling laat zien in POST-verzoeken naar /wp-admin/admin-ajax.php en /wp-cron.php, de host geen 429's meer geeft voor die URL's, en autosave nog steeds werkt in de post-editor (dat is de check die je vertelt dat Heartbeat nog leeft).
Fix voor oorzaak 4: een Cloudflare-rate-limiting-regel staat te strak
Open het Cloudflare-dashboard, ga naar Security > WAF > Rate limiting rules en zoek de regel waarvan de naam matcht met de falende URL. De symptomen vertellen je hoe je hem moet aanpassen:
- Gaat de regel af op een
/wp-json/*-endpoint en blokkeert hij je eigen integraties: zet het bron-IP van je integratie op een allowlist (via Security > WAF > Tools > IP Access Rules, maak een "Allow"-entry), of verhoog de drempel op de regel zelf. De meeste Cloudflare-rate-limit-regels staan standaard op "10 verzoeken per 10 seconden"; voor een drukke integratie is "60 verzoeken per 10 seconden" realistischer. - Gaat de regel af op
/wp-login.phpen blokkeert hij je monitor: zet de bekende IP-ranges van je monitor op een allowlist. - Is de regel uit een security-artikel gekopieerd en weet je niet meer waarom hij bestaat: verwijder hem, en als de 429's terugkomen voeg je een smallere regel toe die alleen het specifieke aanvalspatroon raakt dat je echt wil stoppen.
Cloudflare-wijzigingen zijn binnen een minuut actief. Verifieer met een directe test vanuit de geblokkeerde bron.
Je weet dat het gelukt is wanneer de client die 429's kreeg van Cloudflare nu 200's krijgt, de Security > Events-log van Cloudflare geen matchende rate-limit-events meer voor die client laat zien, en de regel nog steeds blokkeert wat hij oorspronkelijk moest blokkeren.
Fix voor oorzaak 5: een host-WAF of securityplugin-regel gaat af
Anders dan bij Cloudflare zijn rate limits van managed hosts aan de edge zelden direct aanpasbaar. De fix-route is:
-
Identificeer de exacte regel via het dashboard of supportteam van de host. WP Engine, Kinsta en SiteGround hebben expliciete tools hiervoor; Cloudways niet, daar heb je een ticket nodig.
-
Komt de 429 van Wordfence of All In One Security: de drempels staan in de instellingen van de plugin (Wordfence > Firewall > All Firewall Options > Rate Limiting, All In One Security > Brute Force > Rename Login Page / Cookie Based Brute Force Prevention). Verhoog de drempel, of voeg een uitzondering toe voor het legitieme verkeer.
-
Komt de 429 van WooCommerce Store API rate limiting die je niet bewust had aangezet: zet hem uit via het filter:
add_filter( 'woocommerce_store_api_rate_limit_options', function ( $options ) { $options['enabled'] = false; return $options; } );Of laat hem aan maar verhoog de drempel (hetzelfde filter accepteert een
limit- enseconds-optie). -
Zit de 429 op een endpoint dat echt meer verkeer trekt dan je hostingplan aankan: cache agressiever aan de edge zodat de origin minder verzoeken ziet, of verplaats de workload naar een dedicated host.
Je weet dat het gelukt is wanneer het specifieke URL-/clientpatroon dat de 429 triggerde dat niet meer doet, en de regel nog steeds misbruikt verkeer vangt.
Wanneer je moet escaleren
Krijg je met de stappen hierboven binnen 30 minuten de oorzaak niet in beeld, draag het incident dan over aan je host of ontwikkelaar. Zorg dat dit in het eerste bericht staat, want dit is wat elke engineer als eerste vraagt:
- De exacte URL die de 429 teruggeeft, of de exacte uitgaande URL waar je site naar belt als de 429 verschijnt.
- De richting: inkomend (een bezoeker krijgt een 429 van jouw site) of uitgaand (jouw site krijgt een 429 van een andere server).
- De timestamp van het falende verzoek, met tijdzone, en of het reproduceerbaar is of alleen sporadisch voorkomt.
- Je stack: hostingtier (shared, VPS, managed, containers), webserver (nginx of Apache met versie), PHP-versie, WordPress-versie, WooCommerce-versie indien geïnstalleerd.
- Staat de site achter Cloudflare of een andere CDN? Zo ja: geeft de 429 ook bij omzeilen via
curl --resolve? - De matchende regel uit de nginx-access-log, inclusief request-URI, status en bron-IP.
- De matchende regel uit de nginx-error-log, met name iets met
limiting requests,limiting connectionsof een Wordfence-/AIOS-/plugin-identifier. - Voor uitgaande 429's: de hooknaam en het aantal gefaalde jobs uit Scheduled Actions, plus welke plugin eigenaar van die hook is.
- De lijst met actieve plugins, vooral alles wat de laatste 48 uur is geïnstalleerd of geüpdatet.
- Of het falende verzoek een
Retry-After-header heeft (en onthoud dat een ontbrekendeRetry-Afterspec-conform is en niet betekent dat de 429 ongeldig is).
Dat allemaal in het eerste bericht sturen scheelt een rondje heen en weer en routeert de ticket direct naar de juiste engineer in plaats van dat hij tussen teams door zwerft.
Hoe je hem wegblijft
Een aanhoudende 429 op een gezonde WordPress-site is bijna altijd een sizing- of kalibratieprobleem, geen securityincident. Vier gewoontes houden hem zeldzaam:
- Draai geen pseudo-cron op een drukke site. Zet
DISABLE_WP_CRONinwp-config.phpen stel een echte cronjob in via de cronplanner in je hostingpaneel (of via WP-CLI als je SSH-toegang hebt) op een interval van 15 minuten. Pseudo-cron is bedoeld voor shared hosts zonder echte cron, en op elke site waar verkeer hoger is dan jobs gaat hij te vaak af. Dit is de grootste reden dat ik zelf veroorzaakte 429's zie verdwijnen. - Hou de Action Scheduler-backlog in de gaten. Staat Tools > Scheduled Actions > Failed op meer dan een handvol entries met dezelfde hook, dan probeert iets dezelfde kapotte call honderden keren opnieuw en zit je ofwel tegen een externe rate limit aan ofwel in een kapotte integratie. Een gezonde site heeft een Failed-kolom in enkele cijfers en ruimt die regelmatig op.
- Stem Heartbeat af op je redactionele workflow, niet op de default. Het standaardinterval van 15 seconden op bewerk-pagina's was bedacht voor WordPress 2.x en soloblogs. Op een multi-auteur-site met 5 gelijktijdige beheerders komt dat neer op 20 POSTs per seconde alleen al vanuit het ingelogde admin-team, en sommige shared hosts zullen dat rate-limiten. Verhoog het interval naar 60 seconden en laat autosave werken.
- Weet welke rate-limit-regels er zijn. Cloudflare-rate-limiting-regels, nginx-
limit_req-blokken, Wordfence-instellingen en host-WAF-regels blijven stil tot ze afgaan. Kopieer je een regel uit een blogpost of volg je een security-checklist, schrijf dan op wat hij doet en onder welke voorwaarden, zodat je volgende maand, als hij een echte gebruiker blokkeert, weet waar je moet kijken. Een rate-limit-regel die je niet terug kunt vinden is erger dan geen regel.
Krijg je die vier goed, dan zijn de enige 429's die je nog ziet precies de 429's die je wil: aanvallers die terecht geremd worden bij de login, en slechte bots die terecht geremd worden bij de REST API. Al het andere is het systeem dat je vertelt dat iets in je eigen configuratie meer verkeer produceert dan zou moeten, en dat is een signaal dat de moeite waard is om naar zijn bron terug te volgen.