Troubleshooting guide · http-status · Published 2026-08-15 · 4 min read
HTTP 429 too many requests
HTTP 429 too many requests: what triggers it, how Retry-After works, and the ordered steps to fix rate limits in APIs, WordPress and Cloudflare.
- ·What triggers 429
- ·Retry window
- ·Fix order
What triggers a 429
A 429 Too Many Requests means a rate limit was crossed for that client, origin, path, or IP. The server answers 429 instead of serving the request, and the Retry-After header tells the client how long to wait before retrying. Your visitor may never see it: browsers render it as "This page isn't working", crawlers collect it as a status, and APIs return it in a JSON body.
The trick with 429 is that it has three very different owners, and the fix depends on which one set the limit:
| Limit owner | Common sign | Who fixes |
|---|---|---|
Server, e.g. nginx limit_req | Access log has a rate-limit entry | The site owner |
| Application, e.g. WordPress, or the API's own guard | 429 with API body, plugin log | The site owner |
| CDN or WAF, e.g. Cloudflare | 429 from Cloudflare edge, often with a Cloudflare branded body | The site owner or the plan tier |
Common causes
- A burst from a bot, a crawler, or a scraping script hammers the site and trips every limit at once.
- A missing retry and backoff in a client: the client sees 429, ignores it, and fires again instantly, which guarantees a permanent 429.
- The WordPress installation has no built-in rate limit, but the host, Cloudflare, or a security plugin applies one that the traffic rules did not account for, e.g. login or XML-RPC bursts.
- Logins or form rate limits trigger from a shared office or VPN IP; every user behind that IP shares one bucket.
- Environment traffic that is ignored by new limits: a deploy pipeline or health check that previously passed now trips the guard.
The fix order
- Read the headers. Run
curland record theRetry-Afterand anyX-RateLimit-*hints. The numbers are the contract. - Identify the owner. A Cloudflare-branded error page means the edge owns it. A nginx
429in the access log means the origin owns it. An API body like"error": "rate limit exceeded"means the application owns it. - Fix the client pattern. Add exponential backoff and honor
Retry-After. A correct client is the difference between a 429 that resolves and one that never does. - Reduce the burst on the server side. If the site is genuinely busy, raise the limit or spread the work. On nginx raise
limit_reqandlimit_connvalues, and make sure the blog cache absorbs the crawl and the authenticated pages are separate. - Tame bots and XML-RPC on WordPress. Turn off
xmlrpc.phpunless you need it, and put a stronger challenge (Managed Challenge) in front ofwp-login.php,xmlrpc.php, andwp-cron.phpbursts. - Engineering exception routes. Add a retry suggestion plus a timeout to any client, and never cap retries below the window the server declares.
# See the full contract of a 429 response
curl -sI https://api.example.com/list
HTTP/2 429
retry-after: 30
x-ratelimit-remaining: 0
429 versus 503 sidebar
The two statuses schedule different futures. 429 says: you are over your budget, wait and retry. 503 says: the server cannot serve this right now, retry later. Use the header you received, not the one you wish existed, because an API client that honors Retry-After on a 503 and a bot that ignores 429 both waste requests.
Prevention
- Build the client with exponential backoff and jitter as the default. Client cannot tell a 429 from a blackout.
- Set the CDN and origin limits at the point of truth, and above the points of needless content.
- Rate-limit by identity (API key, user) instead of IP where possible, and document the 429 limits for your users.
- Wire the
Retry-Aftervalue into your support docs: your users should see the same number you do.
When to involve a professional
If the site tripped 429s at genuine audience level during a campaign, the budget itself is too small, not the client. The host or platform support will state the limit and the correct tier without guessing.