What is database connection pooling, and why does it matter?

C# Data Access Intermediate 2–3 Yrs3–5 Yrs Conceptual 1 min read

Quick Answer

Opening a physical database connection (TCP handshake, auth, TLS) is expensive. ADO.NET keeps a pool of open connections keyed by the exact connection string; new SqlConnection(...).Open() borrows one and Dispose() returns it. So you should open connections as late and close them as early as possible — the pool makes that cheap.

Establishing a real connection to SQL Server involves a network round-trip, authentication and often TLS, which is slow. So ADO.NET pools connections: when you open one it hands you an idle physical connection from the pool, and disposing it returns it rather than closing it. That's why the guidance is counter-intuitive — open late, dispose immediately, don't hold a connection open for the lifetime of a request. The classic bug is not disposing, usually a missing using; those connections stay checked out until finalization and under load you hit the max pool size and start getting timeout exceptions.

  • Always wrap connections in using — a leaked (undisposed) connection is held out of the pool until GC finalises it, and enough leaks exhaust the pool (Timeout expired after Max Pool Size, default 100).
  • Connection strings must match exactly (including credentials) to share a pool.
  • EF Core manages this for you; DbContext itself is not pooled unless you use AddDbContextPool.
  • Symptoms of leaks: intermittent pool-timeout exceptions under load that clear after a restart.