In JMeter's JDBC Connection Configuration, what does Max Number of Connections set to 0 mean?
answer
- Zero is not unlimited
- It decides sharing, not a ceiling
- Each thread can own its connection
- Positive values make threads queue
basics
~20 sZero turns off sharing. Each JMeter thread lazily builds its own DBCP pool holding a single connection, so no thread ever waits on another. Any positive number builds one pool of that size shared by every thread.
solid answer
~50 sThe field sizes the DBCP `BasicDataSource` that the config element builds. With a positive value **N**, JMeter creates one pool at test start with `maxTotal` and `maxIdle` set to N and shares it across every thread; a thread that finds it empty blocks for up to **Max Wait (ms)** (default `10000`) and then the sample fails with an SQLException. With `0` — the shipped default, and what the manual recommends for most cases — no shared pool is built: the first time each thread asks for a connection it gets its own private pool of exactly one, created on the spot and held for the rest of the run. The thread count then decides how many connections the database sees, and threads never contend. The manual's advice if you do share is to set N equal to the thread count, which defeats the point of sharing.
go deeper
Recall that 0 is the default and means each thread gets its own connection rather than an unlimited pool, and that a positive number is a shared pool of exactly that size.
Explain both shapes: one shared DBCP pool built at test start versus a lazily built per-thread pool of one, and what Max Wait (ms) does when a shared pool runs dry.
Demonstrate reading a run where an undersized shared pool produced failed samples after the Max Wait timeout, and show that the waiting time sits inside the sample's own elapsed and connect times.
Own the decision of what the pool represents in the team's plans, and the rule for when a plan may pin a shared size rather than let the thread count set the number of connections.
`Max Number of Connections` is the most consequential field on JMeter's JDBC Connection Configuration, and `0` does not mean "unlimited" — it means "do not share". ## What the field actually builds The config element wraps Apache Commons DBCP. When the value is a positive number **N**, the element builds one `BasicDataSource` at test start with `maxTotal` and `maxIdle` both set to N, `minIdle` 0, `initialSize` N, and `maxWaitMillis` taken from the **Max Wait (ms)** field. That single pool object is stored under the pool's Variable Name and every thread in the plan borrows from it. When the value is `0`, no shared data source is built. Instead the element stores a wrapper, and the first time a given thread calls for a connection the wrapper builds a pool of size **1** for that thread alone and keeps it in a per-thread map for the rest of the run. Every subsequent JDBC Request on that thread borrows and returns the same physical connection. ## The two shapes side by side | | `Max Number of Connections` = 0 | `Max Number of Connections` = N | |---|---|---| | Pools built | one per thread, size 1 | one, shared by all threads | | Built when | lazily, on that thread's first request | at test start | | Connections the database sees | equal to the number of running threads | at most N | | Threads waiting for a connection | never | any beyond N, up to Max Wait (ms) | | Cost of the first sample per thread | includes opening that thread's connection | paid by the first sampler that borrows — or at test start if Preinit Pool is ticked | ## What Max Wait (ms) does With a shared pool, `Max Wait (ms)` is the ceiling on how long a thread will block inside the pool waiting for a free connection. Its default is `10000`. When that expires, the pool throws, the JDBC Request sampler catches the SQLException and marks the sample failed. The exception comes from the pool, not from the driver, so it carries no SQLState: the response code reads `null 0` and the response message is `Cannot get a connection, pool error ...`. So an undersized shared pool does not merely slow a run down — past the timeout it starts producing failed samples, and the missing SQLState is what tells you the failure formed inside JMeter rather than at the database. Because the sampler calls `sampleStart()` *before* it asks the pool for a connection, that waiting time is inside the sample's elapsed time. The sampler marks the connection-acquisition point as soon as the pool hands a connection over, so the acquire cost is also recorded as the sample's connect time. ## Related fields you should know about - **Preinit Pool** (default `false`) — when false, connection establishment for the pool is paid by the first requests that use it, so the earliest samples of a run read high. Ticking it borrows and returns a connection as the pool is built, which opens the pool's connections then — at test start for a shared pool, but inside the thread's first sample at `0`, where it buys nothing. - **Test While Idle** (default `true`) and **Validation Query** — JMeter hands the query to the pool only when Test While Idle is on, and then it is run both by the idle-object evictor and once when the pool is created; leave the query blank and DBCP falls back to the driver's own `isValid()` check, which suits most databases. - **Time Between Eviction Runs (ms)** (default `60000`) and **Soft Min Evictable Idle Time(ms)** (default `5000`) — how often the evictor runs and how long a connection may idle before it is eligible for eviction. - **Auto Commit** (default on) and **Transaction Isolation** (default `DEFAULT`, meaning the driver's own) — applied to connections as they are handed out. ## Choosing 1. **Default to `0`.** The manual says to set it to zero in most cases, and it is the shipped default. Every thread gets a connection, nothing queues inside JMeter, and the plan's concurrency at the database is exactly the thread count. 2. **Use a positive N when you deliberately want the pool to be the constraint** — for instance to reproduce the size of a real application's pool. Then be ready for blocked threads and, past Max Wait, failed samples. 3. **Do not set N smaller than the thread count by accident.** The manual's own advice for shared pooling is to make N equal to the number of threads so that threads do not wait on each other, which is another way of saying that sharing rarely buys you anything in a load plan. 4. **Remember the per-thread pool is per thread, not per plan.** A 500-thread group with `0` opens 500 database connections; that number is a decision, not a side effect.
- With Max Number of Connections at 0 and a 500-thread group, how many database connections does the run open?Up to 500 — one per thread, each in its own pool of size one, created the first time that thread runs a JDBC Request and held until the test ends. The connections appear gradually as threads start rather than all at once, because each pool is built lazily on first use.
- What does Preinit Pool change about the first samples of a run?It defaults to false, so the cost of opening the pool's connections is paid by the first JDBC Requests that use it and those samples read higher than later ones. Ticking it makes the config element borrow and immediately return a connection when the pool is built. On a shared pool that happens at test start, so the cost leaves the measured samples; at the default 0 the pool is built inside the thread's first JDBC Request, after timing has started, so the tick moves nothing.
A positive Max Number of Connections is a rack of shared car keys: more drivers than keys means someone stands at the rack until a key comes back, and after Max Wait (ms) they give up. Zero hands every driver their own car for the whole run.
saying these in an interview costs you the question
- Reads 0 as an unlimited or unbounded pool
- Thinks a shared pool is always faster than per-thread
- Ignores Max Wait (ms) when the pool is undersized
- Assumes pool exhaustion only slows samples, never fails them
- Believes per-thread pools are built at test start