What is `server.tomcat.max-connections` and how does it differ from `threads.max` and `accept-count`?
answer
- max-connections=8192 hold ceiling (incl. idle keep-alive)
- threads.max=200 run ceiling
- accept-count=100 backlog after max-connections
- NIO poller decouples hold vs run
- -1 = unlimited; watch ulimit -n
basics
~10 smax-connections (default 8192) caps how many connections Tomcat will accept and hold at once. threads.max (200) caps how many run concurrently; accept-count (100) is the OS backlog once max-connections is reached.
solid answer
~40 sWith the NIO connector, Tomcat separates *accepting/holding* a connection from *processing* it. `server.tomcat.max-connections` (default 8192) is the ceiling on concurrently accepted connections — including idle keep-alive ones parked on the poller. `server.tomcat.threads.max` (default 200) is the far smaller pool that actively runs request handlers. So you can hold thousands of mostly-idle keep-alive connections (8192) while only 200 are executing at any instant. When accepted connections reach max-connections, the acceptor stops accepting and new connections wait in the OS backlog sized by `accept-count` (default 100); when that fills, connections are refused. This three-tier model (max-connections ≥ backlog; threads.max = active concurrency) lets Tomcat serve many keep-alive clients cheaply on NIO without a thread per connection, which is why max-connections is much larger than threads.max.
code
yaml · 9 linesserver:
tomcat:
max-connections: 8192 # default; connections accepted & held at once (incl. idle keep-alive)
threads:
max: 200 # default; connections actively processed at once
accept-count: 100 # default; OS backlog once max-connections is reached
keep-alive-timeout: 60000 # how long an idle keep-alive connection is held
max-keep-alive-requests: 100 # requests per connection before close
# max-connections (hold) >> threads.max (run) is the intended NIO relationship.go deeper
May only know these are 'connection limits'; the distinction is advanced.
Should distinguish accept-count from thread pool; may blur max-connections.
Clearly separates hold (max-connections) vs run (threads.max) vs backlog (accept-count) and the NIO poller rationale.
Reasons about keep-alive interplay, file descriptors, -1 unlimited risk, and why WebFlux uses a different model entirely.
## Why there are three separate limits On the classic BIO connector it was one-thread-per-connection, so connections and threads were effectively the same limit. Modern Tomcat defaults to the **NIO connector**, which decouples the two using a *poller*: a connection can be accepted and parked (e.g. an idle HTTP keep-alive connection between requests) without holding a worker thread. That decoupling is exactly why three distinct properties exist. ### `server.tomcat.max-connections` — the acceptance ceiling - Maximum number of connections the server will **accept and hold simultaneously**, active or idle-keep-alive. - **Default: 8192** (NIO). - The acceptor thread counts up to this. When reached, it **stops accepting** new connections until existing ones close. ### `server.tomcat.threads.max` — the execution ceiling - Worker threads that actually **run** request handlers. **Default: 200.** - This is your true *concurrency* limit for in-flight request processing. - It is intentionally *much smaller* than max-connections because most held connections are idle between requests (keep-alive) and don't need a thread. ### `server.tomcat.accept-count` — the overflow backlog - Once **max-connections** is hit, further inbound connections wait in the **OS TCP accept backlog**, sized by `accept-count`. **Default: 100.** - Backlog full → OS refuses the connection. ## The layered flow ``` incoming TCP connection │ ├─ accepted while current connections < max-connections (8192) ── held on NIO poller │ └─ dispatched to a worker thread when one is free (threads.max = 200) │ └─ if connections == max-connections → wait in accept-count backlog (100) └─ backlog full → connection refused ``` ## Gotchas & subtleties - **max-connections includes idle keep-alive connections.** A flood of clients that open connections and keep them alive can exhaust max-connections even if request throughput is low. Tuning `server.tomcat.keep-alive-timeout` / `max-keep-alive-requests` interacts here. - **max-connections ≥ threads.max by design.** Making max-connections smaller than threads.max is almost always a misconfiguration. - **Special value −1** for max-connections means *unlimited* (bounded only by OS/file descriptors) — risky in production. - **File descriptors:** each connection is an FD; a high max-connections needs an adequate `ulimit -n`. - **Reactive/WebFlux** on Netty uses an event loop, not this thread/connection model, so these Tomcat properties don't apply there. - **Load balancer interplay:** behind an LB doing connection pooling, held connections count against max-connections even when idle. ## When to tune Raise max-connections for services fronting many keep-alive clients (mobile, browser HTTP/1.1 pools); raise threads.max only when downstream capacity supports more concurrent processing. They are tuned for different reasons: one for how many you *hold*, one for how many you *run*.
- Why is the default max-connections (8192) so much larger than threads.max (200)?Because the NIO connector parks idle keep-alive connections on a poller without a dedicated thread. You can hold thousands of mostly-idle connections while only ~200 are actively being processed, so the hold limit is naturally far larger than the run limit.
- A service holds many idle keep-alive connections and starts refusing new ones despite low request rate. What's happening and what would you tune?Idle keep-alive connections count against max-connections, exhausting it. Lower `keep-alive-timeout` / `max-keep-alive-requests` so idle connections close sooner, and/or raise max-connections (with adequate file-descriptor ulimit).
saying these in an interview costs you the question
- Saying max-connections equals the thread count
- Claiming idle keep-alive connections don't count toward max-connections
- Thinking max-connections must be smaller than threads.max
- Applying these Tomcat properties to a WebFlux/Netty app