A Single Rate Limit Bucket Lets One Bad Client Starve Everyone Else

Key takeaway: A global rate limit protects your infrastructure and says nothing about fairness between clients. Per-client limiting is a different mechanism solving a different problem, and most APIs need both.
What a Global Limit Actually Protects
A rate limit capping total requests per second across the whole API protects the backend from being overwhelmed, which is a real and necessary concern. It says nothing about how that capacity is distributed among the clients sending those requests — a single client sending requests aggressively can legitimately consume the entire allowed rate, leaving genuinely well-behaved clients receiving rejected requests despite having sent far fewer of their own.
This is not a bug in the global limit; it is simply not the problem a global limit is designed to solve. Protecting the server and ensuring fair access among clients are two distinct concerns that require two distinct mechanisms, and treating a global limit as though it also solves fairness is where the gap appears.
The Distinction in Practice
| Mechanism | Protects against | Does not address |
|---|---|---|
| Global rate limit | Server overload | Fairness between individual clients |
| Per-client rate limit | One client crowding out others | Total server load if many clients each stay under their limit |
| Both together | Server overload and client fairness | Neither alone is sufficient |
A per-client limit, scoped to an API key, user account or IP address depending on what identity is available, ensures no single caller can exceed their fair share regardless of how aggressively they send requests, and combining it with a global limit protects the server even if every client individually stays within their own allowance but the number of clients grows large enough that the aggregate still exceeds server capacity.
Where Per-Client Limiting Gets Complicated
Identifying “a client” is not always straightforward. An API key is a clean identifier when available. An IP address is a weaker proxy, because many legitimate users can share one IP behind a corporate network or mobile carrier NAT, and limiting by IP alone can unfairly throttle all of them for the behaviour of one, while an attacker distributing requests across many IPs evades an IP-based limit entirely regardless of total request volume.
Authenticated APIs should generally rate-limit by the authenticated identity rather than by IP, since it is both a more accurate proxy for “one client” and harder for a single bad actor to trivially evade by rotating addresses.
Communicating Limits to Clients
Returning the standard rate limit headers — remaining quota, reset time — on every response, not only on responses that hit the limit, lets well-behaved clients self-regulate proactively rather than discovering the limit only by being rejected. This is a small addition with a real effect on how gracefully clients behave, because a client that can see it is approaching its limit can slow down voluntarily rather than continuing at full speed until rejected.
Returning a clear retry-after value on rejection, rather than a generic rejection with no guidance, lets well-implemented clients back off appropriately rather than immediately retrying and compounding the load that triggered the limit in the first place.
Handling Legitimate Bursts
Pure fixed-window rate limiting — resetting the count sharply at each window boundary — creates an artificial cliff at the boundary that does not reflect genuine usage patterns, where a client can send a burst just before a window resets and another burst just after, doubling their effective rate briefly around the boundary. Token bucket or sliding window algorithms handle bursty-but-legitimate traffic more gracefully than a hard fixed-window reset, at the cost of slightly more complex implementation.
The Bottom Line
Implement both a global rate limit protecting server capacity and a per-client limit protecting fairness between callers, since neither alone addresses what the other does. Identify clients by authenticated identity rather than IP where authentication is available, return rate limit status on every response rather than only on rejection, and prefer a token bucket or sliding window over a hard fixed-window reset to handle legitimate bursty traffic gracefully.



