HTTP 429 Too Many Requests: what it means and how to fix it

HTTP 429 means the server is rate limiting you: too many requests arrived in a short time. Usually the fix is to wait (at least as long as the `Retry-After` header says) and then send fewer requests. If you run the server, check that your limits aren't too tight.

Applies to:Any HTTP client or server (web servers, proxies, CDNs, APIs)nginxlimit_req_status needs 1.3.15+; limit_req delay= needs 1.15.7+
On this page

What it means

A 429 response is the server telling a client to slow down. The client sent more requests in a given period than the server is willing to accept, so the server refuses the extra ones. It is defined in RFC 6585 and is not tied to any particular HTTP version.

The response may carry a Retry-After header. Its value is either a number of seconds or an HTTP date, and a well-behaved client should handle both. The body is supposed to explain what happened. Caches must not store a 429 response.

The standard doesn't say who gets counted. A server may count per IP address, per user or credential, per cookie, per resource, or across the whole server. Servers also aren't required to use 429 at all: under attack or heavy load they may simply drop the connection.

This article covers the status itself and the usual places you meet it: browsers, API clients and server configuration. Each provider sets its own limits and header names, so check your provider's documentation for the exact numbers.

Symptoms and causes

You are likely dealing with this problem if:

  • A browser page reading "429 Too Many Requests", or a vendor-styled page saying the same thing.
  • API calls return 429 with a JSON or HTML body, often with a Retry-After header.
  • Scripts, scrapers or CI jobs work for a while, then start failing after a burst of requests.
  • Some services use 403 instead for rate limits (GitHub does this), so the same problem can show up under a different code.

The usual causes, most common first:

Too many requests from your client
The usual triggers are a retry or polling loop with no delay, a tight loop, many parallel workers, or bulk and scraper traffic.
A shared IP address
Limits are usually applied per IP. If a NAT, VPN, proxy or office or cloud network funnels many people through one address, they may all share one bucket. This is an inference from per-IP limiting rather than something the docs state outright.
API quota reached for a user or token
Services such as GitHub have primary limits (a quota that resets) and secondary limits (protection against abuse and bursts).
Server-side limits set too tight
In nginx, limit_req with burst=0 (the default) rejects excess requests immediately. The status is 503 by default and becomes 429 only when limit_req_status 429; is set.
A CDN or WAF rule blocked you
On Cloudflare a visitor hitting a rate limiting rule sees error 1015. The block lasts for the rule's mitigation timeout: 10 seconds on Free, up to 1 hour on Pro, up to 1 day on Business and Enterprise. Cloudflare's page does not say which HTTP status accompanies that error, so don't assume it is a 429.
Continuing to send requests while limited
Hammering a service that is already limiting you can extend the block and may get the integration banned (GitHub documents this).

How to fix it

Work through these in order. They start with the quickest, safest checks and move to deeper repairs; stop as soon as the problem is gone.

1.Wait, then retry once

Easy

Rate limits reset with time. Refreshing repeatedly can make the wait longer.

  1. Stop refreshing the page or re-running the request.
  2. If the response includes a Retry-After header, wait at least that long. If it doesn't, the response gives no wait time, so check the provider's rate limit documentation for the reset window.

2.Honor Retry-After and back off in your client

Moderate

A client that waits as instructed stops triggering the limit and avoids extending the block.

  1. Read Retry-After when a 429 arrives. Use it as seconds when it is a number. If it is absent, use exponential backoff with random jitter and cap the number of retries.
    Text
    const ra = res.headers.get("Retry-After");
    const delayMs = ra && !isNaN(ra) ? Number(ra)*1000 : 2**attempt*1000 + Math.random()*1000;
  2. Also handle the case where Retry-After holds an HTTP date instead of a number of seconds.

3.Cut down unnecessary requests

Moderate

Most 429s come from the client sending more than it needs to.

  1. Find loops and polling that run without a delay, and remove duplicate requests.
  2. Cache responses that haven't changed, and throttle requests on the client side.
  3. If you really need more throughput, ask the provider about a higher quota, a different plan or an authenticated token. The steps are vendor-specific.

4.Handle GitHub API rate limits

Moderate

GitHub documents exactly how long to wait depending on which limit you hit.

  1. For a primary rate limit, don't retry until the time in the x-ratelimit-reset header (UTC epoch seconds).
  2. For a secondary limit with a retry-after header, wait that many seconds.
  3. For a secondary limit where x-ratelimit-remaining is 0, wait until x-ratelimit-reset.
  4. For a secondary limit with neither header, wait at least one minute, then back off exponentially if it continues.
  5. Use the x-ratelimit-* headers on normal responses to pace your requests before you hit the limit.

5.Tune nginx request limiting (server admins)

AdvancedChanges settings

If legitimate users get rejected, your limit_req settings may be too strict, or may be returning 503 instead of 429.

Before you start: Back up your nginx configuration and run nginx -t before reloading. Test new limits with dry run first so you don't block real users.

  1. Set a zone, a burst allowance and the rejection status. The burst queue absorbs spikes, nodelay serves burst requests immediately, and delay=N (nginx 1.15.7+) is a middle option.
    nginx.conf
    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
    
    server {
        location /search/ {
            limit_req zone=one burst=5 nodelay;
            limit_req_status 429;
        }
    }
  2. Before enforcing a new limit, turn on limit_req_dry_run on; and log $limit_req_status. It reports PASSED, DELAYED, REJECTED or the DRY_RUN variants.
  3. Size the zone memory sensibly: about 16,000 states fit per MB on 32-bit and 8,000 on 64-bit. When the zone is full, the least recently used state is evicted. Requests with an empty key are not counted.

6.Review Cloudflare rate limiting rules (site owners)

ModerateChanges settings

A rule that is too aggressive blocks real visitors, who see error 1015.

Before you start: Be careful with verified bots: rate limiting them can affect your search visibility. Note your current rule settings before changing them.

  1. In the Cloudflare dashboard, open the rate limiting rule that is matching and review its characteristics, period, requests per period, duration and expression.
  2. Raise the request threshold or narrow the expression so it only matches the paths you want to protect.
  3. Keep in mind that counting can lag by a few seconds, so some excess requests may still reach your origin. Enterprise plans can throttle instead of blocking.

Check that it worked

  • The same request now returns a 2xx status instead of 429.
  • Your client logs show no further 429 responses under normal load.
  • For server changes, the $limit_req_status log shows PASSED for normal traffic and REJECTED only for genuine bursts.

If it still fails

  • Read the full response headers and body: Retry-After and any x-ratelimit-* or RateLimit-* headers tell you which limit you hit and when it resets. Names differ by provider.
  • Check whether you are really seeing 503 (server overloaded or unavailable) or 403 (forbidden). These are different problems with different fixes.
  • Contact the service's support, or check its rate limit documentation, if you believe the limit is wrong for your plan.
  • If you run the server, confirm which layer is returning the status: the application, a reverse proxy, or a CDN or WAF in front.

Questions

Is 429 the same as 503?

No. 429 means you sent too many requests. 503 means the server is overloaded or unavailable. nginx returns 503 for rate-limited requests by default unless limit_req_status 429; is set.

Does a 429 mean I've been banned?

Not usually. It is normally a temporary limit. Continuing to send requests while limited can extend the block or lead to a ban on some services, so back off.

Sources

  1. 429 Too Many Requests | MDN Web Docs · MDN Web Docs (Mozilla)
  2. RFC 6585 §4: 429 Too Many RequestsOfficial · IETF / RFC Editor
  3. ngx_http_limit_req_moduleOfficial · nginx.org
  4. Rate limiting rulesOfficial · Cloudflare Docs
  5. Rate limits for the REST APIOfficial · GitHub Docs