Safeguard
Security Guides•

nginx limit_conn versus limit_req: which limit for which problem

limit_conn caps concurrent connections per key and limit_req caps request rate. Use each for the right problem, with HTTP/2 counting and dry run to test.

Safeguard Security Team
3 min read

limit_req controls how fast requests arrive. limit_conn controls how many are in flight at once. Use limit_req for login and API abuse, limit_conn for downloads and slow clients. Many sites need both, with different keys, and both support a dry run mode so you can test before blocking anyone.

What each one measures

limit_req counts arrivals over time, per key, using a rate such as 5r/s with an optional burst. It answers: is this client sending too many requests?

limit_conn counts concurrent connections per key. The docs say a connection is counted only when it has a request being processed and the whole request header has been read. It answers: is this client holding too many slots open?

Pick by problem

ProblemBetter fit
Password guessing on /loginlimit_req with a low rate
Scraping a cataloglimit_req with a modest burst
One client opening many slow downloadslimit_conn per address
One virtual server overwhelmedlimit_conn on server name
Slow request tricklingtimeouts first, then limit_conn

A combined example

limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name        zone=perserver:10m;
limit_req_zone  $binary_remote_addr zone=login:10m rate=5r/s;

server {
    limit_conn perip 10;
    limit_conn perserver 100;
    limit_conn_status 429;

    location /login {
        limit_req zone=login burst=10 nodelay;
        limit_req_status 429;
    }
}

This follows the pattern in the nginx documentation, which shows 10 connections per client address and 100 per virtual server.

Details that surprise people

  • In HTTP/2 and HTTP/3, each concurrent request counts as a separate connection for limit_conn. A browser opening many parallel streams can hit a low limit quickly, so do not copy an HTTP/1 number.
  • Several limit_conn directives are inherited only if the current level defines none. The same holds for limit_req.
  • Both default to status 503. Choose 429 on purpose.
  • If a zone is exhausted, limit_conn returns the error to further requests. Size zones for your peak, remembering one megabyte holds about 16,000 64-byte states.
  • Behind a proxy or balancer, the key is the balancer's address unless you set up real client address handling. See the real_ip post. A per address limit on the wrong address blocks everyone at once.

Test with dry run

Both modules have a dry run directive, off by default. In this mode traffic is not limited, but excess is still counted, and a status variable ($limit_conn_status or $limit_req_status) reports what would have happened. Add it to your log format and run for a day.

Limits of these tools

They key on an address. Attackers with many addresses and users sharing one NAT both break that model. Pair them with account level controls and monitoring, as listed in the API resource limits checklist.

Try it yourself

Open the demo and click through the API scan. Look for findings about missing limits on endpoints.

Click through it at your own pace, or open it full screen.

Quick check

Which directive stops one client from holding many concurrent downloads?

limit_conn, keyed on the client address.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.