Connection Pooling
Size and configure database connection pools so async services do not exhaust PostgreSQL max_connections or stall under load.
Busca en todas las páginas de la documentación
Size and configure database connection pools so async services do not exhaust PostgreSQL max_connections or stall under load.
Quick-reference recipe card - copy-paste ready.
let pool = sqlx::postgres::PgPoolOptions::new()
.max_connections(20)
.min_connections(5)
.acquire_timeout(std::time::Duration::from_secs(5))
.connect(&database_url)
.await?;When to reach for this: Every server process talking to PostgreSQL, MySQL, or Redis should reuse a pool - never open per request.
use sqlx::postgres::PgPoolOptions;
#[derive(Clone)]
struct AppState { pool: sqlx::PgPool }
async fn sizing_hint(workers: u32, db_max: u32, services: u32) -> u32 {
// rule of thumb: pool_max * service_replicas * workers <= db_max * 0.8
let per_instance = (db_max as f32 * 0.8 / services as f32).floor() as u32;
per_instance.min(20).max(2)
}
#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
let max = sizing_hint(4, 100, 3).await;
let pool = PgPoolOptions::new()
.max_connections(max)
.connect(&std::env::var("DATABASE_URL")?)
.await?;
let _state = AppState { pool };
Ok(())
}What this demonstrates:
max_connections caps concurrent DB sessions per process.min_connections keeps warm connections for latency.acquire_timeout fails fast when pool is starved.acquire_timeout.deadpool-postgres and bb8 are alternatives for other drivers.instances × pool_max ≤ database_max_connections × 0.7–0.8
Leave headroom for admin connections, migrations, and replicas.
// deadpool-postgres (alternative)
let cfg = deadpool_postgres::Config::from_url(&url)?;
let pool = cfg.create_pool(None, tokio_postgres::NoTls)?;AppState at startup.| Alternative | Use When | Don't Use When |
|---|---|---|
| sqlx built-in pool | sqlx stack | Need deadpool ecosystem features |
| PgBouncer | Many small services | Single monolith with few connections |
| Single connection | One-shot CLI scripts | HTTP servers |
One pool per process - Tokio tasks share it, not one per thread.
deadpool-redis or multiplexed connections per redis crate guidance.
SELECT 1 through pool for /ready endpoint.
Track acquire time, idle count, and timeouts with tracing or Prometheus.
pool.close().await during graceful shutdown.
Two pools pointing to primary and replica URLs.
max_lifetime recycles old connections - set for cloud DB failovers.
sqlx caches prepared statements per connection - watch memory on huge pools.
Ramp until acquire timeouts appear - that is your real ceiling.
Very small pools or external pooler (PgBouncer) required - cold starts matter.
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.
Revisado por Chris St. John·Última actualización: 16 jul 2026