Why Connection Pooling?
Without pooling, every query requires expensive connection setup:
| Operation | Without Pooling | With Pooling |
|---|---|---|
| TCP handshake | Every query | Once |
| TLS handshake | Every query | Once |
| Authentication | Every query | Once |
| Overhead per query | 10-50ms | <1ms |
Why Proxy-Level Pooling Matters
Even if your application has connection pooling, a proxy-level pool provides critical advantages:
1. Defense Against Connection Explosions
Applications can misbehave and create too many connections:
App Instance 1: 50 connections (configured)
App Instance 2: 50 connections
App Instance 3: 200 connections (BUG: pool leak!)
App Instance 4: 50 connections
─────────────────────────────────
Total: 350 connections → Database overwhelmed!
With ScryData:
All instances → ScryData (pool: 100) → Database
↑
Hard limit enforced, database protected
2. Centralized Observability
Application-level pools give you per-instance metrics. ScryData gives you centralized visibility:
- Total query load across all applications
- Slow queries from any service
- Hot data patterns across your entire system
- Pool utilization for the entire database
3. Multi-Language Environments
Different languages/frameworks have different pooling quality:
- Node.js app: Good pooling library
- Python app: Mediocre pooling configuration
- Legacy Java app: No pooling (connections per request!)
- PHP app: No persistent connections
ScryData provides consistent pooling regardless of application implementation.
4. Deploy-Time Flexibility
- Scale applications independently without reconfiguring database
- Add new services without coordinating connection limits
- Change pool settings without redeploying applications
- Roll out connection pooling to legacy apps without code changes
Connection Lifecycle
1. Creation
TCP connect → TLS handshake (if enabled) → Authentication → Add to pool
2. Acquisition
Check circuit breaker → Get from pool or create new → Health check → Return to caller
3. Recycling
Health check (SELECT 1) → State reset (DISCARD ALL) → Return to pool
State Reset: DISCARD ALL
Every connection is reset before reuse with DISCARD ALL:
- Temporary tables
- Prepared statements
- Session variables
- Transaction state
- Cursors
- Advisory locks
This ensures connections are "clean" for the next query, preventing state leakage between different clients.
Configuration
| Parameter | Default | Description |
|---|---|---|
pool_size |
10 |
Maximum connections in pool |
pool_timeout_secs |
30 |
Timeout waiting for available connection |
connection_timeout_ms |
5000 |
Timeout for creating new connection |
Sizing Guidelines
Formula: pool_size ≥ (peak_qps × avg_query_latency_secs) + buffer
| Traffic | QPS | Avg Latency | Recommended Pool Size |
|---|---|---|---|
| Low | 100 | 10ms | 10 |
| Medium | 1,000 | 10ms | 30 |
| High | 10,000 | 10ms | 150 |
| High Latency | 1,000 | 100ms | 150 |
Pool Metrics
curl http://localhost:9090/debug/pool
{
"size": 15,
"available": 8,
"max_size": 50,
"utilization": 0.46
}
Interpretation:
- size: Current number of connections (active + idle)
- available: Idle connections ready for use
- max_size: Maximum configured pool size
- utilization: (size - available) / max_size
- 0.0 = no connections in use
- 1.0 = all connections in use (saturated)
Prometheus Metrics
scry_pool_connections_total 15
scry_pool_connections_available 8
scry_pool_connections_max 50
scry_pool_utilization 0.46
Troubleshooting
Pool Exhaustion
Symptoms: Queries timing out, utilization = 1.0
Solutions:
- Increase pool size
- Optimize slow queries
- Check for connection leaks in applications
Slow Pool Acquisition
Symptoms: High pool_acquire_ms in timeline metrics
Solutions:
- Check pool saturation
- Increase pool size if saturated
- Verify database responsiveness
Protect Your Database From Connection Overload
ScryData enforces hard connection limits while providing deep observability.
Request Early Access