PostgreSQL Connection Pool Exhausted Hatası Nasıl Çözülür? PgBouncer Rehberi (2026)

01.01.2026 03:29 Haber

PostgreSQL veritabanınızda "The connection pool has been exhausted" veya "FATAL: sorry, too many clients already" hatası mı alıyorsunuz? Alesta Web olarak bu rehberde connection pool sorunlarını nasıl teşhis edip çözeceğinizi (how to fix) adım adım anlatacağız. Production ortamlarında bu hata kritik olabilir!

Connection Pool Nedir? (What is Connection Pool?)

Veritabanı bağlantısı oluşturmak pahalı bir işlemdir. Her istek için yeni bağlantı açmak yerine, önceden oluşturulmuş bağlantıları havuzda tutup yeniden kullanmak çok daha verimlidir. İşte bu mekanizmaya Connection Pooling denir.

Alesta Web olarak yüksek trafikli projelerde connection pool yönetiminin ne kadar kritik olduğunu biliyoruz. Yanlış yapılandırma, uygulamanızı tamamen çökertebilir!

Hata Mesajları / Error Messages:

# Npgsql (C#/.NET)
NpgsqlException: The connection pool has been exhausted,
either raise 'Max Pool Size' (currently 100) or 'Timeout' (currently 15 seconds)

# PostgreSQL Native
FATAL: sorry, too many clients already

# Connection Timeout
Exception: Timeout expired. The timeout period elapsed prior to obtaining
a connection from the pool.
? Bilgi / Info:

PostgreSQL varsayılan olarak maksimum 100 bağlantıya izin verir (max_connections). Her backend process bellek tüketir, bu yüzden sınırsız bağlantı açamazsınız.

Hata Nedenleri (Common Causes)

Alesta Web deneyimlerimize göre connection pool exhausted hatasının başlıca nedenleri:

1. Connection Leak (Bağlantı Sızıntısı)

❌ Hatalı Kod / Buggy Code:

// C# - Bağlantı kapatılmamış!
public void GetData()
{
    var conn = new NpgsqlConnection(connectionString);
    conn.Open();
    var cmd = new NpgsqlCommand("SELECT * FROM users", conn);
    var reader = cmd.ExecuteReader();
    // ... işlemler
    // ❌ conn.Close() veya using yok - LEAK!
}

// Python - Bağlantı kapatılmamış!
def get_data():
    conn = psycopg2.connect(DATABASE_URL)
    cursor = conn.cursor()
    cursor.execute("SELECT * FROM users")
    # ❌ conn.close() yok - LEAK!
    return cursor.fetchall()

2. Uzun Süren Sorgular (Long-Running Queries)

Yavaş sorgular bağlantıyı uzun süre meşgul tutar ve havuz tükenir.

3. Yetersiz Pool Size

Trafik artarken pool size sabit kalırsa, bağlantı açılamaz.

4. Yanlış Timeout Ayarları

Çok kısa timeout değerleri, yoğun anlarda hatalara neden olur.

5. Idle Bağlantılar

Kullanılmayan bağlantılar havuzda yer kaplar ve diğer istekleri bloklar.

⚠️ Production Uyarısı / Production Warning:

Connection leak production ortamında en tehlikeli sorunlardan biridir. Başlangıçta fark edilmez, ancak zamanla bağlantılar tükenir ve uygulama çöker!

Teşhis Yöntemleri (Diagnosis Methods)

Alesta Web olarak sorunun kaynağını bulmak için şu adımları izliyoruz:

1. Aktif Bağlantıları Kontrol Et

PostgreSQL Sorguları / PostgreSQL Queries:

-- Toplam aktif bağlantı sayısı
SELECT count(*) FROM pg_stat_activity;

-- Veritabanına göre bağlantılar
SELECT datname, count(*)
FROM pg_stat_activity
GROUP BY datname
ORDER BY count(*) DESC;

-- State'e göre bağlantılar
SELECT state, count(*)
FROM pg_stat_activity
GROUP BY state;

-- Detaylı bağlantı bilgisi
SELECT
    pid,
    usename,
    application_name,
    client_addr,
    state,
    query_start,
    NOW() - query_start AS query_duration,
    LEFT(query, 50) AS query_preview
FROM pg_stat_activity
WHERE state != 'idle'
ORDER BY query_start;

2. max_connections Değerini Kontrol Et

Konfigürasyon Kontrolü:

-- max_connections değeri
SHOW max_connections;

-- Tüm connection ayarları
SELECT name, setting, unit, context
FROM pg_settings
WHERE name LIKE '%connection%'
   OR name LIKE '%pool%';

-- Kalan bağlantı kapasitesi
SELECT
    max_conn.setting::int AS max_connections,
    used_conn.count AS current_connections,
    max_conn.setting::int - used_conn.count AS available
FROM
    (SELECT setting FROM pg_settings WHERE name = 'max_connections') max_conn,
    (SELECT count(*) FROM pg_stat_activity) used_conn;

3. Uzun Süren Sorguları Bul

Yavaş Sorgu Tespiti:

-- 30 saniyeden uzun süren sorgular
SELECT
    pid,
    NOW() - query_start AS duration,
    query,
    state
FROM pg_stat_activity
WHERE (NOW() - query_start) > INTERVAL '30 seconds'
  AND state != 'idle';

-- Blocking sorgular
SELECT
    blocked.pid AS blocked_pid,
    blocked.query AS blocked_query,
    blocking.pid AS blocking_pid,
    blocking.query AS blocking_query
FROM pg_catalog.pg_locks blocked_locks
JOIN pg_stat_activity blocked ON blocked.pid = blocked_locks.pid
JOIN pg_catalog.pg_locks blocking_locks
    ON blocking_locks.locktype = blocked_locks.locktype
    AND blocking_locks.relation = blocked_locks.relation
JOIN pg_stat_activity blocking ON blocking.pid = blocking_locks.pid
WHERE NOT blocked_locks.granted
  AND blocked_locks.pid != blocking_locks.pid;

Çözüm Yöntemleri (Solutions)

Çözüm 1: Connection Leak'leri Düzelt

✅ Doğru Kod / Correct Code:

// C# - Using statement ile otomatik dispose
public async Task<List<User>> GetUsersAsync()
{
    await using var conn = new NpgsqlConnection(connectionString);
    await conn.OpenAsync();

    await using var cmd = new NpgsqlCommand("SELECT * FROM users", conn);
    await using var reader = await cmd.ExecuteReaderAsync();

    var users = new List<User>();
    while (await reader.ReadAsync())
    {
        users.Add(new User { Id = reader.GetInt32(0) });
    }
    return users;
}  // ✅ Otomatik olarak kapatılır

# Python - Context manager ile
def get_users():
    with psycopg2.connect(DATABASE_URL) as conn:
        with conn.cursor() as cursor:
            cursor.execute("SELECT * FROM users")
            return cursor.fetchall()
    # ✅ Otomatik olarak kapatılır

# Node.js - Pool ile
const { Pool } = require('pg');
const pool = new Pool({ max: 20 });

async function getUsers() {
    const client = await pool.connect();
    try {
        const result = await client.query('SELECT * FROM users');
        return result.rows;
    } finally {
        client.release();  // ✅ Pool'a geri ver
    }
}

Çözüm 2: max_connections Artır

postgresql.conf Düzenleme:

# /etc/postgresql/15/main/postgresql.conf

# Varsayılan: 100
max_connections = 200

# Shared buffers da artırılmalı (bağlantı başına ~1MB)
shared_buffers = 512MB

# Restart gerekli
sudo systemctl restart postgresql

# Veya reload ile (bazı ayarlar için)
SELECT pg_reload_conf();
⚠️ Dikkat / Warning:

max_connections artırmak kısa vadeli çözümdür. Her bağlantı bellek tüketir. 500+ bağlantı için mutlaka connection pooler (PgBouncer) kullanın!

Çözüm 3: Pool Ayarlarını Optimize Et

Connection String Örnekleri:

# C# / Npgsql
Host=localhost;Database=mydb;Username=user;Password=pass;
Maximum Pool Size=100;Minimum Pool Size=10;Connection Idle Lifetime=300;
Connection Pruning Interval=10;Timeout=30

# Node.js / pg
const pool = new Pool({
    host: 'localhost',
    database: 'mydb',
    max: 20,                    // Maximum pool size
    idleTimeoutMillis: 30000,   // Idle timeout
    connectionTimeoutMillis: 5000  // Connection timeout
});

# Python / SQLAlchemy
engine = create_engine(
    'postgresql://user:pass@localhost/mydb',
    pool_size=20,
    max_overflow=10,
    pool_timeout=30,
    pool_recycle=1800
)

Çözüm 4: Idle Bağlantıları Sonlandır

Idle Bağlantı Temizleme:

-- 10 dakikadan uzun idle bağlantıları sonlandır
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle'
  AND query_start < NOW() - INTERVAL '10 minutes'
  AND pid != pg_backend_pid();

-- Otomatik temizlik için postgresql.conf
idle_in_transaction_session_timeout = '5min'
idle_session_timeout = '10min'  -- PostgreSQL 14+

PgBouncer Kurulumu (Connection Pooler)

Yüksek trafikli uygulamalar için PgBouncer veya PgPool-II kullanmanızı şiddetle tavsiye ediyoruz. Alesta Web olarak tüm production projelerimizde PgBouncer kullanıyoruz.

PgBouncer Kurulumu (Ubuntu):

# Kurulum
sudo apt update
sudo apt install pgbouncer

# Konfigürasyon dosyası
sudo nano /etc/pgbouncer/pgbouncer.ini

pgbouncer.ini Örneği:

[databases]
mydb = host=127.0.0.1 port=5432 dbname=mydb

[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt

# Pool mode: session, transaction, statement
pool_mode = transaction

# Pool ayarları
default_pool_size = 20
max_client_conn = 1000
max_db_connections = 50

# Timeouts
server_idle_timeout = 600
query_timeout = 120

# Logging
log_connections = 1
log_disconnections = 1

userlist.txt Oluşturma:

# Kullanıcı hash'i oluştur
psql -U postgres -c "SELECT concat('\"', usename, '\" \"', passwd, '\"') FROM pg_shadow;"

# /etc/pgbouncer/userlist.txt
"myuser" "md5hashburaya"

# Servisi başlat
sudo systemctl enable pgbouncer
sudo systemctl start pgbouncer

# Uygulama artık 6432 portuna bağlanacak
postgresql://myuser:pass@localhost:6432/mydb
✅ PgBouncer Avantajları / PgBouncer Benefits:
  • 1000+ client bağlantısını 20-50 PostgreSQL bağlantısına sıkıştırır
  • Bağlantı overhead'ini minimize eder
  • Transaction pooling ile maksimum verimlilik
  • Connection leak'lere karşı koruma

Best Practices (En İyi Uygulamalar)

Alesta Web olarak PostgreSQL bağlantı yönetimi için şu kurallara uyuyoruz:

? Altın Kurallar / Golden Rules:
  • ✅ Her zaman using/context manager kullan
  • ✅ Connection pooler (PgBouncer) kullan
  • ✅ Pool size'ı iş yüküne göre ayarla
  • ✅ Monitoring kur (pg_stat_activity izle)
  • ✅ Timeout'ları makul değerlere ayarla
  • ✅ Yavaş sorguları optimize et
  • ✅ Idle bağlantıları temizle

Monitoring Script

Basit Monitoring Sorgusu:

-- Her 5 dakikada çalıştır
SELECT
    NOW() AS check_time,
    (SELECT count(*) FROM pg_stat_activity) AS total_connections,
    (SELECT count(*) FROM pg_stat_activity WHERE state = 'active') AS active,
    (SELECT count(*) FROM pg_stat_activity WHERE state = 'idle') AS idle,
    (SELECT count(*) FROM pg_stat_activity
     WHERE state = 'idle in transaction') AS idle_in_tx,
    (SELECT setting::int FROM pg_settings
     WHERE name = 'max_connections') AS max_conn;

? Kaynaklar ve Referanslar / Sources and References

Alesta Web olarak tüm çözümleri production ortamlarında test ettik.

✅ Sorun Çözüldü! (Problem Solved!)

Artık PostgreSQL connection pool exhausted hatası (bağlantı havuzu tükendi) sizin için sorun olmaktan çıktı! Alesta Web olarak PgBouncer kurulumu ve doğru pool yönetimi ile veritabanı performansınızı maksimize edebilirsiniz.

Hızlı Özet / Quick Summary:

  • ✅ Connection pool kavramı anlaşıldı (Pool concept understood)
  • ✅ Leak'ler tespit edildi ve düzeltildi (Leaks fixed)
  • ✅ PgBouncer kuruldu (PgBouncer installed)
  • ✅ Best practices uygulandı (Best practices applied)

Faydalı Linkler / Useful Links:

© 2026 AlestaWeb - Tüm hakları saklıdır.

WM Tools
💫

WebMaster Tools

15 Profesyonel Araç