Skip to main content
๐Ÿ“œ WAYPOINT LESSON

Connection lifecycle and pooling

โญโญโญ advancedโณ 15 min read๐Ÿ“ Lesson 256 of 265

Open late, close early: why connections are pooled, what pool exhaustion looks like, and the leak patterns that cause it.

Connection lifecycle and pooling

Opening a real database connection costs a TCP handshake, auth, and session setup โ€” milliseconds you pay per logical operation if you are careless. So ADO.NET (and every driver above it) keeps a pool: Close() returns the connection to the pool; the physical socket stays warm. Two rules follow.

Open late, close early. Hold a connection only while a query is running โ€” not while you compute, not while you call another service. A connection held across a remote HTTP call is the classic "site slows to a crawl at 3 p.m." bug: the pool is finite (default max 100), and once every connection is checked out, the next caller blocks waiting for one until Connection Timeout (default 15 s) expires with InvalidOperationException: Timeout expired... The connection pool has been exhausted.

The leak patterns that exhaust pools:

  • No using/await using around the connection (exception path skips Close).
  • Returning a connection-holding object (reader, command) from a method.
  • Holding the connection while awaiting unrelated I/O.
  • Dynamic connection strings โ€” the pool keys on the exact string, so per-tenant connection strings silently create per-tenant pools.

Pool exhaustion is a concurrency symptom: a single-user test never sees it. That is why the challenge models occupancy arithmetic instead of real connections โ€” the reasoning transfers unchanged.

Language note: connection strings are configuration, not code. Secrets therefore belong in configuration/secrets management (module 23), never in source. (EN content; VI translation ships alongside per the loader contract.)