429 Too Many Requests Error: Causes and How to Fix It
If your site or an API call is throwing a 429 Too Many Requests error, something between the visitor and your server has decided there are too many requests coming from one place, too fast. It's not a crash — it's a limit doing exactly what it was configured to do. The trick is finding out which limit, and whether it's protecting you or getting in your own way.
What a 429 Actually Means
HTTP 429 is a client-side status code, but that label is misleading. It usually doesn't mean a visitor typed too fast — it means some layer in the request path (your app, your web server, a CDN, or a security module) counted requests from an IP, session, or API key and hit a ceiling. The response often includes a Retry-After header telling the client how long to wait, though not every server bothers to send one.
You'll see it in a few different shapes depending on where it's coming from:
- A plain browser page saying "429 Too Many Requests" or "Rate limit exceeded"
- A WordPress site that loads the theme but fails to load posts, images, or REST API data
- An API integration (payment gateway, Google Maps, a plugin's remote service) silently failing with a 429 in its logs
- Cloudflare's own rate-limiting or "I'm Under Attack" challenge page
Common Causes
1. Your hosting stack's own rate limiting
Shared and VPS environments running LiteSpeed, Apache with mod_evasive, or ModSecurity often cap requests per IP per second to stop abuse. A single visitor hammering AJAX endpoints, or a badly written script polling an endpoint every second, can trip this even though nothing malicious is happening.
2. A misbehaving plugin or cron job
This is the most common cause we see on WordPress sites. A plugin that polls a REST endpoint on every page load, a broken cron entry firing every minute instead of every hour, or a security plugin doing IP lookups on each request can generate enough internal traffic to trigger your own server's limits.
3. Cloudflare or another CDN/WAF rule
If you're proxying through Cloudflare, its rate-limiting rules or bot-fight mode can return a 429 before the request ever reaches your server. This is worth checking first, because the fix lives entirely in the Cloudflare dashboard, not in your hosting.
4. Bots, scrapers, or a login brute-force attempt
A flood of requests hitting /wp-login.php, /xmlrpc.php, or a search page is a classic sign of automated scraping or credential-stuffing. Rate limiting here is doing its job — the fix is to block the source, not raise the limit.
5. Third-party API limits
Google Maps, Mailchimp, Stripe, and similar services enforce their own per-key rate limits. If your site embeds a map or syncs orders and starts throwing 429s in the browser console, the limit may belong to the third party, not your server.
How to Diagnose It
Before changing any settings, figure out which layer is issuing the 429. Work through this in order:
- Check the response headers. Run
curl -I https://yourdomain.com/pathfrom a terminal. Look for aRetry-Afterheader or aServerheader that hints at Cloudflare, LiteSpeed, or nginx. - Check Cloudflare first, if you use it. In the dashboard, go to Security > Events and filter for 429 or "rate limit" actions. If you see hits there, that's your source.
- Check the Apache/LiteSpeed error log. In cPanel, open Metrics > Errors, or via SSH tail
/usr/local/apache/logs/error_log(or the equivalent domlogs path for your account). ModSecurity blocks usually log a rule ID alongside the 429/403. - Check WordPress-specific logs. Enable
WP_DEBUG_LOGinwp-config.phpand watchwp-content/debug.logwhile reproducing the issue — this catches plugins making excessive REST or cron calls. - Check server load at the time of the error. Run
topor check the cPanel Resource Usage graphs. If CPU or the process count spikes right before the 429s appear, something is generating a burst of internal requests, not external ones.
How to Fix It
If it's your server's rate limiting (ModSecurity / mod_evasive)
In cPanel, go to Security > ModSecurity and check for triggered rules against the affected URL. If a specific rule is too aggressive for legitimate traffic (common with REST API-heavy sites), you can disable that rule for the domain rather than turning off ModSecurity entirely. On a VPS with WHM, adjust the rate limit thresholds under Plugins > ModSecurity Vendors, or edit the evasive module's DOSPageCount and DOSSiteCount values in the Apache config.
If it's a plugin or cron job
Deactivate plugins one by one (or use a staging copy) while watching whether the 429s stop. For cron, run wp cron event list via WP-CLI to see what's scheduled and how often. A job that should run hourly but is firing every minute is a common culprit — fix the schedule or the plugin causing it.
If it's Cloudflare
Go to Security > WAF > Rate Limiting Rules and either raise the threshold for the affected path or exclude it (for example, your own REST API endpoints used by a mobile app). If Bot Fight Mode is blocking legitimate automated traffic — like a webhook from a payment provider — add that provider's IP range to an allow rule.
If it's an actual attack
Don't raise the limit — block the source. Use CSF (ConfigServer Security & Firewall) on a VPS to block the offending IPs, or turn on Cloudflare's "Under Attack" mode temporarily. For WordPress login attacks specifically, rename or restrict access to wp-login.php and disable xmlrpc.php if you don't use it.
If it's a third-party API
Check that service's dashboard for your current usage against your plan's limit. Often the fix is caching the API response locally (for example, caching a Google Maps embed or a shipping-rate lookup) so you're not calling the API on every page load.
Preventing It From Happening Again
| Prevention step | Why it helps |
|---|---|
| Cache API responses and REST data where possible | Cuts the number of outbound requests that could hit a limit |
| Audit cron schedules after installing new plugins | Catches runaway jobs before they trigger internal rate limits |
| Set sane Cloudflare rate-limiting thresholds instead of defaults | Avoids blocking real users during traffic spikes |
| Monitor error logs weekly, not just when something breaks | Surfaces slow-building issues like a misfiring cron before it becomes a full outage |
| Keep a current backup and staging site | Lets you test plugin changes without touching production |
Most 429 errors trace back to something inside your own stack calling itself too often — not an external attack. Start with your logs, confirm which layer issued the error, and fix that one thing instead of loosening every limit at once.
Frequently asked questions
Does a 429 error mean my site is under attack?
Not necessarily. It's just as likely to be your own plugin, cron job, or CDN rate-limiting rule triggering on legitimate traffic. Check your logs before assuming it's malicious - only block IPs once you've confirmed the traffic isn't coming from your own site or a service you use.
Why am I seeing 429 errors only on wp-login.php or xmlrpc.php?
That pattern usually points to a brute-force or credential-stuffing attempt. Your rate limiting is working as intended. Block the source IPs with CSF or your firewall, and disable xmlrpc.php entirely if you don't use it for anything like the Jetpack or WordPress mobile app.
How do I know if Cloudflare or my server is issuing the 429?
Run curl -I against the affected URL and check the Server header, or check Cloudflare's Security > Events log for rate-limit actions. If Cloudflare shows no matching events, the block is happening at your server or application layer instead.
Can I just raise the rate limit to make the error go away?
You can, but it treats the symptom, not the cause. If a plugin or cron job is generating excessive requests, raising the limit just delays the same problem at a higher traffic volume. Find and fix the source first, then adjust limits only if legitimate traffic still needs more headroom.