Setiap kali sebuah aplikasi membuka koneksi ke MySQL, server mengalokasikan satu thread beserta memori buffer untuknya — dan koneksi yang tidak dikelola bisa menggerus resource justru pada saat server paling sibuk. Administrasi koneksi memuat pertanyaan-pertanyaan yang pasti muncul di produksi: berapa koneksi maksimum yang sanggup ditampung, bagaimana membedakan koneksi yang benar-benar bekerja dengan yang sekadar menganggur, kapan koneksi idle diputus otomatis, dan mengapa aplikasi tiba-tiba ditolak dengan error “Too Many Connections”. Chapter ini membedah variabel-variabel pengatur koneksi dan statusnya di server latihan, lalu menutup dengan praktik connection pooling dari sisi aplikasi.
max_connections dan Model Thread #
Batas paling mendasar adalah max_connections — jumlah koneksi simultan maksimum yang diterima server. Kita baca tiga variabel yang membentuk gambaran utuhnya:
SHOW VARIABLES LIKE 'max_connections';
SHOW VARIABLES LIKE 'max_user_connections';
SHOW VARIABLES LIKE 'thread_handling';Output yang Dihasilkan:
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| max_connections | 151 |
+-----------------+-------+
1 row in set (0.00 sec)
+----------------------+-------+
| Variable_name | Value |
+----------------------+-------+
| max_user_connections | 0 |
+----------------------+-------+
1 row in set (0.00 sec)
+-----------------+---------------------------+
| Variable_name | Value |
+-----------------+---------------------------+
| thread_handling | one-thread-per-connection |
+-----------------+---------------------------+
1 row in set (0.00 sec)Nilai max_connections 151 adalah default MySQL; max_user_connections 0 berarti tiap user tidak punya batas khusus (hanya batas global yang berlaku); dan thread_handling bernilai one-thread-per-connection — model default Community Server tempat satu thread OS lahir untuk setiap koneksi. Model ini sederhana dan adil untuk ratusan koneksi, tetapi ribuan koneksi akan melahirkan ribuan thread yang saling berebut CPU context-switch — pada skala itu, edisi Enterprise menawarkan thread pool yang mengantri pekerjaan ke sekelompok thread tetap. Sebelum menaikkan max_connections, ingat bahwa tiap koneksi membawa keuntungan biaya: memori stack dan buffer per koneksi dikalikan jumlahnya, sehingga nilai besar di server ber-RAM kecil justru mempercepat kehabisan memori.
Threads_connected vs Threads_running #
Dua counter status memberitahu kondisi koneksi sekarang — keduanya dibaca dengan SHOW STATUS:
SHOW STATUS LIKE 'Threads_connected';
SHOW STATUS LIKE 'Threads_running';Output yang Dihasilkan:
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| Threads_connected | 1 |
+-------------------+-------+
1 row in set (0.00 sec)
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| Threads_running | 2 |
+-----------------+-------+
1 row in set (0.00 sec)Threads_connected menghitung koneksi klien yang sedang terbuka — di server latihan hanya ada 1, yaitu sesi kita sendiri. Threads_running menghitung thread yang sedang sibuk mengeksekusi pekerjaan; nilainya bisa sedikit lebih besar dari koneksi kita karena thread internal server (misalnya event scheduler) ikut dihitung. Pasangan ini adalah denyut nadi server: Threads_connected yang merangkak mendekati max_connections berarti habisnya slot koneksi, sedangkan Threads_running yang tinggi terus-menerus berarti banyak query berat berjalan bersamaan — dua gejala berbeda dengan obat yang berbeda. Di shell terminal, mysqladmin ping memastikan jalur koneksi TCP ke port 3306 selalu hidup:
-- @test-bash
mysqladmin -h 127.0.0.1 -P 3306 -u root pingOutput yang Dihasilkan:
mysqld is aliveRespons mysqld is alive menegaskan server menerima koneksi baru pada port tersebut.
Timeout Koneksi Idle: wait_timeout dan interactive_timeout #
Koneksi yang dibiarkan terbuka tanpa aktivitas memakan slot max_connections tanpa manfaat. Server membersihkannya lewat dua variabel kembar:
SHOW VARIABLES LIKE 'wait_timeout';
SHOW VARIABLES LIKE 'interactive_timeout';Output yang Dihasilkan:
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout | 28800 |
+---------------+-------+
1 row in set (0.00 sec)
+---------------------+-------+
| Variable_name | Value |
+---------------------+-------+
| interactive_timeout | 28800 |
+---------------------+-------+
1 row in set (0.00 sec)Keduanya default 28800 detik (8 jam), tetapi keduanya melayani tipe klien berbeda: koneksi non-interaktif (aplikasi, skrip batch) memakai wait_timeout, sedangkan klien interaktif seperti mysql CLI memakai interactive_timeout. Hubungan ini nyata terasa saat kita mengubah nilai globalnya. Kita turunkan interactive_timeout ke 77 detik, lalu periksa wait_timeout dari sesi baru:
SET GLOBAL interactive_timeout = 77;Output yang Dihasilkan:
Query OK, 0 rows affected (0.00 sec)SHOW VARIABLES LIKE 'wait_timeout';
SET GLOBAL interactive_timeout = 28800;Output yang Dihasilkan:
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout | 77 |
+---------------+-------+
1 row in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)Sesi interaktif baru membaca wait_timeout 77 — diambil dari interactive_timeout global saat koneksi dibuka. Kita kembalikan nilainya ke 28800 pada statement kedua supaya server latihan pulih. Praktik umum produksi: interactive_timeout dan wait_timeout di-set beberapa ratus detik saja, cukup panjang untuk sesi kerja singkat namun memutus koneksi yang terlupakan dalam menit, bukan jam. Sebaliknya, connection pooling justru menginginkan umur koneksi panjang — dua kebijakan yang harus dipilih salah satu arahnya per aplikasi.
max_connect_errors dan Host yang Diblokir #
Variabel max_connect_errors melindungi server dari klien yang gagal terus-menerus:
SHOW VARIABLES LIKE 'max_connect_errors';Output yang Dihasilkan:
+--------------------+-------+
| Variable_name | Value |
+--------------------+-------+
| max_connect_errors | 100 |
+--------------------+-------+
1 row in set (0.00 sec)Setiap gagal handshake dari sebuah host (kredensial salah, koneksi putus di tengah jalan) menaikkan pencatat kesalahan host itu di host cache. Begitu melewati 100 (nilai default), server menolak total koneksi dari host tersebut dengan ERROR 1129 (HY000): Host '...' is blocked — bukan lagi soal sandi, melainkan hukuman blokir. Ketika ini terjadi di lapangan biasanya justru bukan penyerang: aplikasi yang crash-loop atau load balancer yang memakai port scan agresif adalah tersangka paling sering. Pemulihannya dengan mengosongkan host cache — perintah FLUSH HOSTS lama sudah dihapus dari MySQL 8.0, dan cara resminya kini adalah TRUNCATE TABLE performance_schema.host_cache atau mysqladmin flush-hosts dari terminal. Server latihan kita tidak pernah terblokir, jadi perintah tersebut cukup kita ketahui sebagai kartu darurat.
Connection Pooling dari Sisi Aplikasi #
Membuka koneksi baru itu mahal: TCP handshake, autentikasi, inisialisasi thread server, dan SSL bila dipakai — semua berulang setiap kali. Connection pooling menjawabnya dengan kolam koneksi yang dibuka sekali lalu dipinjamkan: aplikasi mengambil koneksi idup dari pool saat butuh dan mengembalikannya setelah selesai, bukan membuka-membuka koneksi baru. Hampir semua bahasa pemrograman memiliki pooling siap pakai — JDBC di Java, SQLAlchemy dengan pool_size di Python, PDO dengan persistent connection di PHP — dan detail pemakaiannya dibahas pada section integrasi aplikasi. Dua parameter pool yang perlu disinkronkan dengan server: ukuran maksimum pool jangan melampaui max_connections yang tersisa setelah dikurangi kebutuhan monitoring dan maintenance, dan umur idle koneksi di pool harus lebih pendek dari wait_timeout supaya server tidak memutus koneksi yang masih dipakai pool diam-diam — bug “server has gone away” klasik lahir dari ketidaksinkronan ini.
Error “Too Many Connections” #
Ketika jumlah koneksi menyentuh max_connections, koneksi berikutnya ditolak dengan ERROR 1040 (HY000): Too many connections. Simulasi error ini dengan jujur butuh membuka 151 koneksi sungguhan — tidak pantas dilakukan di server latihan kita — jadi cukup dipahami dari sisi penanganannya. Respons pertama yang benar bukan langsung menaikkan max_connections, melainkan membuka satu sesi admin lalu menjawab: siapa yang memegang seluruh koneksi itu? Perintah SHOW PROCESSLIST (topik chapter berikutnya) memperlihatkan seluruh koneksi beserta statusnya — biasanya kita akan menemukan ratusan baris Sleep: koneksi idle yang dipeluk aplikasi tanpa dipakai. Solusinya bisa memperketat timeout, memperbahi pooling aplikasi, lalu barulah menaikkan max_connections bila beban memang tumbuh. MySQL menyisakan satu slot khusus: koneksi dengan privilege CONNECTION_ADMIN tetap diterima melewati batas, supaya admin bisa masuk untuk membereskan kekacauan.
Referensi #
- Connection Management — MySQL 8.4 Reference Manual
- Server System Variables — MySQL 8.4 Reference Manual
- mysqladmin — MySQL 8.4 Reference Manual
Kita sudah tahu cara menghitung dan membatasi koneksi. Pertanyaan berikutnya justru lebih tajam: koneksi nomor berapa yang sedang membuat server tersengal, dan apa query yang sedang dijalaninya? Jawabannya ada di SHOW PROCESSLIST — chapter berikutnya.