
Pesan mysql too many connections berarti batas koneksi bersamaan tercapai. Penyebabnya hampir selalu bukan batas yang terlalu kecil, melainkan koneksi yang tidak pernah ditutup atau kueri lambat yang menahan koneksi lebih lama dari seharusnya.
Solusi pertama yang muncul di hampir setiap forum adalah menaikkan `max_connections`. Itu memang menghilangkan pesan errornya, untuk sementara.
Masalahnya, batas itu ada dengan alasan. Setiap koneksi memakan memori, dan menaikkannya tanpa memeriksa apa yang mengisinya berarti menukar satu kegagalan dengan kegagalan lain yang lebih sulit dipulihkan.
Lihat dulu siapa yang memakai koneksinya
Sebelum mengubah konfigurasi, satu perintah menjawab hampir semuanya: `SHOW PROCESSLIST` — atau `SHOW FULL PROCESSLIST` supaya kueri tidak terpotong.
Yang dicari adalah pola. Banyak baris dengan status `Sleep` berarti koneksi terbuka tanpa mengerjakan apa pun. Banyak baris dengan kueri yang sama dan waktu berjalan tinggi berarti ada kueri lambat yang menumpuk. Baris dengan status `Locked` atau `Waiting for table metadata lock` berarti ada yang saling menunggu.
Ketiga pola itu punya perbaikan yang berbeda, dan itulah kenapa menaikkan batas tanpa melihat dulu adalah tembakan dalam gelap.
Kueri lambat menahan koneksi lebih lama
Pola kedua lebih halus. Ketika kueri lambat menahan koneksi, jumlah koneksi bersamaan naik bukan karena trafik bertambah, tetapi karena setiap permintaan bertahan lebih lama.
Hitungannya sederhana. Kalau satu permintaan memakai koneksi selama 50 milidetik, seratus permintaan per detik hanya butuh sekitar lima koneksi bersamaan. Kalau kuerinya melambat menjadi dua detik, jumlah yang sama butuh dua ratus koneksi — dan batasnya tersentuh tanpa ada perubahan trafik sama sekali.
Karena itu batas koneksi yang tercapai sering merupakan gejala performa, bukan gejala kapasitas. Memperbaiki kueri lambatnya menyelesaikan keduanya sekaligus.
Max connections mysql: menghitung batas yang wajar
Setelah penyebabnya ditangani, barulah pantas meninjau nilai max connections mysql. Angkanya tidak bisa ditebak — ia dibatasi memori.
Setiap koneksi memakai memori untuk buffer per-koneksi seperti `sort_buffer_size` dan `join_buffer_size`. Total memori MySQL kira-kira buffer global — terutama `innodb_buffer_pool_size` — ditambah jumlah koneksi dikali buffer per-koneksi.
Artinya menaikkan jumlah koneksi mengurangi memori yang tersedia untuk buffer pool, dan buffer pool yang mengecil membuat semua kueri lebih lambat. Ada titik di mana menaikkan batas justru memperburuk keadaan.
Praktik yang kami pakai: hitung kebutuhan koneksi dari jumlah worker aplikasi, bukan dari tebakan. Kalau ada tiga server aplikasi dengan lima puluh worker masing-masing, batas 200 sudah masuk akal; kalau satu server dengan dua puluh worker, 100 sudah longgar.
Kapan menaikkan max connections memang benar
Ada kondisi di mana menaikkan max connections adalah jawaban yang tepat, dan menahannya justru merugikan. Beberapa di antaranya:
- Jumlah server aplikasi bertambah, sehingga kebutuhan koneksinya memang naik secara sah.
- Batasnya masih pada nilai bawaan 151 padahal server punya memori besar dan beban nyata melampauinya.
- Ada beberapa aplikasi berbeda berbagi satu basis data, masing-masing dengan pool sendiri.
- Anda memakai proxy koneksi seperti ProxySQL yang memang membuka banyak koneksi ke belakang.
- Sedang menangani lonjakan sementara dan butuh waktu untuk perbaikan yang benar — dengan catatan itu dicatat sebagai utang, bukan solusi.
Menyiapkan diri sebelum terjadi lagi
Kejadian ini punya sifat yang tidak menyenangkan: ketika batas tercapai, Anda juga tidak bisa masuk untuk memeriksanya. MySQL menyisakan satu koneksi untuk pengguna dengan hak `SUPER`, jadi pastikan ada akun administratif yang memilikinya — bukan hanya akun aplikasi.
Selain itu, pemantauan pada tiga angka ini memberi peringatan jauh sebelum batasnya tersentuh: jumlah koneksi aktif, `Threads_connected` dibanding `max_connections`, dan jumlah kueri lambat per menit.
Yang terakhir paling berguna sebagai peringatan dini. Kenaikan kueri lambat hampir selalu mendahului masalah koneksi, jadi ia memberi waktu bertindak sebelum ada yang mengeluh.
Menangani saat kejadian, tanpa memperburuk
Ketika batas sudah tercapai dan aplikasi mati, urutan tindakan berikut memulihkan layanan tanpa menghapus jejak penyebabnya.
Ada satu pola yang layak diwaspadai pada aplikasi modern: setiap instance aplikasi membuka pool koneksinya sendiri. Menambah satu container atau satu server aplikasi berarti menambah sekumpulan koneksi baru ke basis data, dan batasnya bisa tersentuh hanya karena penskalaan yang berhasil.
Karena itu ukuran pool perlu dihitung terhadap jumlah instance maksimum, bukan jumlah sekarang. Pada lingkungan yang menskalakan otomatis, ini termasuk hal pertama yang kami periksa.
- Masuk dengan akun yang punya hak `SUPER` — koneksi cadangan yang disisakan MySQL memang untuk ini.
- Jalankan `SHOW FULL PROCESSLIST` dan simpan keluarannya sebelum apa pun dihentikan.
- Hentikan koneksi yang jelas menganggur lama dengan `KILL`, mulai dari yang statusnya `Sleep` dan waktunya paling besar.
- Kalau ada satu kueri yang berjalan sangat lama dan menahan yang lain, hentikan itu juga — catat kuerinya untuk diperbaiki.
- Turunkan `wait_timeout` untuk sesi berikutnya bila koneksi menganggur memang penyebabnya.
- Setelah pulih, baru periksa log kueri lambat untuk penyebab yang sebenarnya.