HTTP status codes / 429
429 Too Many Requests — HTTP Status Code
A 429 Too Many Requests response means the client sent more requests than the server allows in a given time window, so the server is refusing more for now. The server is working; it is throttling. Wait, ideally for the time given in the Retry-After header, and send requests more slowly.
What 429 means
429 Too Many Requests means "you are sending requests too fast; slow down." It is defined in RFC 6585, Section 4, which describes it as the response to a user who has sent too many requests in a given amount of time. The RFC deliberately leaves the counting to the server: limits can be per IP address, per API key, per user, per endpoint or across a whole cluster.
The response should explain the limit, and it may include a Retry-After header with either a delay in seconds or an HTTP date. RFC 6585 also says a 429 must not be cached.
When you see it
- APIs return 429 when a key or account exceeds its quota, often with extra headers describing the limit and remaining calls.
- Web servers and proxies return it when a per-IP limit in nginx, HAProxy or a similar layer is exceeded.
- CDNs and WAFs such as Cloudflare return it when a rate limiting rule fires, before the request reaches your origin.
- Login and search pages often have tighter limits than the rest of a site, to slow down brute-force and scraping.
Who sends it matters. A 429 with your CDN's branding came from the edge; a 429 in your application's JSON format came from your code.
Common causes
- A script, crawler or integration sending requests in a tight loop without delays.
- Many clients behind one IP address, such as an office network, a mobile carrier or a CI runner, sharing one per-IP budget.
- Retry logic that retries immediately on failure, multiplying traffic exactly when the server is already refusing it.
- A limit set too low for real traffic, often after a burst-free limit is applied to pages that load many API calls at once.
- Monitoring or health checks from several tools hitting the same endpoint more often than expected.
How to fix it
If you are the client:
- Honor
Retry-Afterwhen it is present. - Otherwise use exponential backoff with jitter, and cap the number of retries.
- Spread requests out, batch where the API allows, and cache responses you fetch repeatedly.
- Ask the provider for a higher quota if your legitimate usage needs it.
If you run the server, tune the limit rather than removing it. In nginx:
limit_req_zone $binary_remote_addr zone=perip:10m rate=10r/s;
server {
location /api/ {
limit_req zone=perip burst=20 nodelay;
limit_req_status 429;
}
}
burst absorbs short spikes, such as a page that fires several API calls at once, and limit_req_status 429 replaces nginx's default of 503. To exempt a trusted client, build the zone key with a map that yields an empty value for it; nginx does not count requests with an empty key. In Cloudflare, adjust the rate limiting rule's threshold and period, or add an exception for known good traffic.
Always send Retry-After with your 429 responses. Well-behaved clients will use it.
How to check it
Send a quick burst and watch the status codes change:
for i in $(seq 1 30); do
curl -s -o /dev/null -w "%{http_code}\n" https://api.example.com/v1/items
done | sort | uniq -c
Then inspect the headers of a throttled response:
curl -sI https://api.example.com/v1/items | grep -i -E "^(HTTP|retry-after|ratelimit|x-ratelimit)"
What it means for uptime monitoring
PingRobot's checker sends one GET per check with the user agent PingRobot/1.0 (+https://pingrobot.io/bot), follows redirects, and counts the final response as up only if its status is 200–399. A 429 counts as down, and the failure is re-checked from a second region before alerting.
A 429 is usually a monitor configuration issue, not an outage: the server is answering, just refusing your checks. Because checks run on Cloudflare's network rather than from fixed IP addresses, a per-IP limit can occasionally group them with other traffic. Two fixes work well:
- Lower the check frequency if a 1-minute interval is more than the endpoint's limit tolerates.
- Allowlist the user agent in your rate limiter, WAF or bot rules. The PingRobot bot page lists the exact user agent to match.
If 429s appear for real users too, treat them as a capacity or limit-tuning problem, because visitors are being turned away.
Related codes
- 503 Service Unavailable – also used for overload, and nginx's default rate-limit code.
- 403 Forbidden – what some WAFs return instead when they block bots outright.
- 408 Request Timeout – the client was too slow, the opposite problem.
- 431 Request Header Fields Too Large – another RFC 6585 code.
- 422 Unprocessable Content – the request was understood but rejected for its data.
Start monitoring free — 10 monitors, no credit card.
Frequently asked questions
How long should I wait after a 429?
If the response has a Retry-After header, wait at least that long. It is either a number of seconds or an HTTP date. Without one, back off exponentially, for example 1, 2, 4 and 8 seconds, with some random jitter.
Why does nginx return 503 instead of 429 when rate limiting?
The nginx limit_req module rejects requests with 503 by default. Add limit_req_status 429; to send the more accurate 429 code.
Is a 429 counted against my site's uptime?
The site is up, but a monitor that only accepts 2xx and 3xx will record a failure. If your own rate limiter is blocking your monitor, exempt the monitor or check less often, rather than accepting 429 as healthy.
Can a 429 response be cached?
No. RFC 6585 says responses with 429 must not be stored by a cache, so a CDN should not keep serving a stale 429 after the limit resets.