Bab 18 sudah membekali kita dengan satu RDBMS yang berjalan penuh di server, lengkap dengan database dan role aplikasi tersendiri untuk webapp_db. PostgreSQL bukan satu-satunya pemain di dunia RDBMS open source, dan Developer yang datang dari latar belakang framework populer seperti Laravel, WordPress, atau berbagai stack PHP dan Node.js lawas hampir pasti pernah bersinggungan dengan nama MySQL. Bab ini melanjutkan Bagian V dengan MySQL sebagai RDBMS kedua yang kita kuasai, mulai dari sejarah singkatnya yang bercabang menjadi MariaDB, instalasi dan pengamanan awal lewat mysql_secure_installation, manajemen user dan privilege dengan model account yang cukup berbeda dari PostgreSQL, hingga membuka akses remote secara aman dan memahami perubahan penting yang dibawa migrasi dari MySQL 8.0 ke 8.4.
19.1 Sejarah Singkat: MySQL vs MariaDB
MySQL pertama kali dirilis pada 1995 oleh perusahaan Swedia bernama MySQL AB, dikembangkan oleh tiga orang termasuk Michael "Monty" Widenius. Nama MySQL sendiri berasal dari nama anak salah satu pendirinya, My, sebuah trivia kecil yang sering dilupakan padahal berhubungan langsung dengan kisah fork yang akan kita bahas sesaat lagi. Perjalanan kepemilikan MySQL berubah drastis dalam kurun waktu singkat: Sun Microsystems mengakuisisi MySQL AB pada 2008, lalu Oracle Corporation mengakuisisi Sun pada 2010, sehingga MySQL kini berada di bawah kendali salah satu vendor RDBMS proprietary terbesar di dunia.
Perpindahan kepemilikan ke Oracle inilah yang memicu kekhawatiran sebagian komunitas open source, terutama soal arah pengembangan jangka panjang dan konsistensi lisensi GPL yang selama ini menjadi fondasi MySQL. Widenius merespons kekhawatiran itu dengan melakukan fork, yaitu menyalin seluruh source code MySQL pada 2009 untuk dikembangkan secara independen di bawah nama proyek baru bernama MariaDB, nama yang lagi-lagi diambil dari nama anaknya yang lain, Maria. MariaDB dirancang agar tetap kompatibel secara luas dengan MySQL, baik dari sisi protokol koneksi, driver client, maupun sintaks SQL dasar, sehingga aplikasi yang ditulis untuk MySQL umumnya bisa langsung berjalan di MariaDB tanpa perubahan kode.
Kompatibilitas itu tidak berlaku selamanya secara sempurna. Kedua proyek terus berkembang secara terpisah selama lebih dari satu dekade, masing-masing menambah fitur sendiri, mengubah default tertentu, dan bahkan mengganti sebagian tooling command line-nya, seperti yang akan kita lihat sendiri saat membahas MariaDB di Bab 20. Ubuntu memasukkan kedua RDBMS ini ke repository resminya sebagai paket terpisah, tetapi sejak beberapa rilis terakhir MariaDB dijadikan pilihan default yang lebih diutamakan di sejumlah tooling Ubuntu, sementara MySQL tetap tersedia penuh bagi Sysadmin yang memang butuh kompatibilitas ketat dengan ekosistem resmi Oracle, misalnya untuk aplikasi enterprise yang secara eksplisit mensyaratkan MySQL.
| Aspek | MySQL | MariaDB |
|---|---|---|
| Pengelola | Oracle Corporation | MariaDB Foundation dan MariaDB Corporation |
| Lisensi inti | GPL v2, dengan edisi Enterprise berbayar tertutup | GPL v2 penuh, seluruh fitur tetap open source |
| Model rilis terbaru | Innovation release tiap 3 bulan, LTS tiap 2 tahun (dibahas di Bagian 19.5) | Rilis major berkala dengan siklus dukungan jangka panjang sendiri |
| Command line tools | mysql, mysqldump, mysqladmin | mariadb, mariadb-dump, mariadb-admin (dibahas di Bab 20) |
| Paket default Ubuntu 26.04 | Tersedia via mysql-server | Default yang direkomendasikan via mariadb-server |
19.2 Instalasi MySQL 8.4 dan mysql_secure_installation
Ubuntu 26.04 LTS menyediakan MySQL 8.4 langsung dari repository resminya, sama seperti PostgreSQL 18 di Bab 18, tanpa perlu menambah repository pihak ketiga milik Oracle. MySQL 8.4 sendiri adalah rilis Long Term Support (LTS) pertama di bawah model rilis baru MySQL, sebuah topik yang kita bahas lebih dalam di Bagian 19.5.
19.2.1 Instalasi Paket dari Repository Ubuntu
Langkah Praktik
- Perbarui daftar paket, lalu pasang MySQL server.
Paketsudo apt update sudo apt install mysql-servermysql-serveradalah meta-package yang otomatis menarikmysql-server-8.0atau versi turunannya yang tersedia di repository, sekaligus menarikmysql-clientsebagai dependency, mirip pola meta-packagepostgresqlyang sudah kita kenal. - Instalasi otomatis membuat data directory di
/var/lib/mysql, menjalankan service-nya, dan mengaktifkannya saat boot. Berbeda dari PostgreSQL yang menamai service-nya sesuai versi major, paket Ubuntu untuk MySQL selalu memakai nama unitmysql.serviceapa pun versinya, sehingga perintah pengecekan status tidak perlu berubah setiap kali MySQL naik versi.sudo systemctl status mysql - Konfirmasi versi MySQL yang benar-benar terpasang.
mysql --version
Verifikasi dan Troubleshooting
- Output
systemctl statusyang sehat menampilkanactive (running). Jika gagal start, periksa log lewatsudo journalctl -u mysql -n 50untuk mencari penyebabnya, biasanya berupa konflik port 3306 dengan instance MySQL/MariaDB lain yang sudah berjalan. - Berbeda dari struktur PostgreSQL di Bab 18 yang memisahkan data dan konfigurasi versi per cluster, MySQL di Ubuntu menyimpan seluruh data di satu direktori flat
/var/lib/mysql, sedangkan konfigurasinya tersebar di/etc/mysql/mysql.conf.d/mysqld.cnfyang di-include lewat file utama/etc/mysql/my.cnf. Perbedaan struktur ini penting diingat karena memengaruhi cara kita mencari file yang tepat saat troubleshooting. - Nomor versi minor yang tampil di
mysql --versionbisa berbeda tergantung kapan repository Ubuntu terakhir disinkronkan, catatan yang sama seperti versi PostgreSQL di Bagian 18.1.2.
19.2.2 Mengamankan Instalasi dengan mysql_secure_installation
Paket mysql-server di Ubuntu memasang account root dengan metode autentikasi auth_socket, sebuah plugin yang mencocokkan nama user OS yang sedang login dengan nama account MySQL yang dituju, cara kerja yang mirip peer authentication PostgreSQL di Bagian 18.2.1. Konsekuensinya, account root MySQL tidak pernah punya password sejak awal instalasi, dan satu-satunya cara masuk sebagai root adalah lewat Unix socket memakai sudo. Script mysql_secure_installation membantu Sysadmin menutup sejumlah celah keamanan bawaan lain yang masih tersisa setelah instalasi selesai.
Langkah Praktik
- Masuk dulu sebagai
rootmemakai socket, membuktikan cara kerjaauth_socketsebelum menjalankan script pengaman.
Ketiksudo mysqlexituntuk keluar setelah promptmysql>muncul tanpa diminta password sama sekali. - Jalankan script pengamanan instalasi.
Script ini lebih dulu menawarkan komponen validate_password, yaitu plugin opsional yang memaksa aturan kompleksitas password (panjang minimum, kombinasi huruf besar/kecil, angka, dan karakter spesial) untuk setiap account baru yang dibuat setelahnya. Menjawab tidak pada tawaran ini aman untuk lingkungan lab karenasudo mysql_secure_installationrootsendiri memang tidak memakai password sama sekali, tetapi server production yang bakal menampung banyak account sebaiknya mengaktifkannya dan memilih levelMEDIUMatauSTRONG. Setelah itu, script mendeteksirootmemakaiauth_socketdan langsung melewati langkah set password untuknya, ditandai pesan yang persis berbunyi seperti berikut.Securing the MySQL server deployment. Skipping password set for root as authentication with auth_socket is used by default. - Script kemudian menanyakan serangkaian pertanyaan Y/n secara interaktif. Jawab
Yuntuk seluruh pertanyaan berikut, karena semuanya menutup celah yang tidak dibutuhkan di server production.Remove anonymous users? [Y/n] Y Disallow root login remotely? [Y/n] Y Remove test database and access to it? [Y/n] Y Reload privilege tables now? [Y/n] Y
Verifikasi dan Troubleshooting
- Pesan penutup
Success. All done!menandakan seluruh langkah berhasil diterapkan. - Menjawab
Ypada pertanyaanDisallow root login remotelytidak benar-benar berarti apa-apa secara teknis di sini, karenarootmemang sudah terkunci hanya lewatauth_socketyang otomatis tidak bisa dipakai dari jaringan luar. Pertanyaan ini lebih relevan untuk server yang akunroot-nya sempat diberi password lewatmysql_native_passwordataucaching_sha2_password. - Catatan dari lapangan: tool manajemen berbasis web seperti phpMyAdmin yang akan kita pasang di Bab 22 tidak bisa memakai
auth_socketsama sekali, karena koneksinya selalu lewat TCP, bukan Unix socket langsung dari proses PHP. Account khusus dengan password, sepertiwebapp_useryang kita buat di Bagian 19.3, tetap wajib disiapkan untuk kebutuhan semacam itu.
19.3 Manajemen User dan Privilege
Skenario di bagian ini meneruskan kebutuhan Developer yang sama seperti Bab 18: sebuah database aplikasi bernama webapp_db, kali ini di MySQL, beserta account aplikasi bernama webapp_user yang terpisah dari root. Cara MySQL memodelkan user sedikit berbeda dari PostgreSQL, dan perbedaan ini penting dipahami sebelum GRANT pertama dijalankan.
19.3.1 Model Akun user@host di MySQL
PostgreSQL menyatukan konsep user dan group ke dalam satu role, sedangkan MySQL memakai model yang disebut account, yaitu pasangan nama user dan host asal koneksi yang dituliskan sebagai 'user'@'host'. Dua account dengan nama user sama tetapi host berbeda, misalnya 'webapp_user'@'localhost' dan 'webapp_user'@'192.168.1.20', dianggap MySQL sebagai dua account yang sepenuhnya terpisah dengan password dan privilege masing-masing, bukan satu user yang kebetulan bisa login dari dua tempat. Nilai host mendukung wildcard % untuk mewakili host mana pun, serta notasi CIDR seperti 192.168.1.0/24 sejak MySQL 8.0.23, mirip gaya penulisan subnet di pg_hba.conf yang sudah kita praktikkan di Bagian 18.4.1.
19.3.2 Membuat Database dan User Aplikasi
Langkah Praktik
- Masuk ke MySQL sebagai
rootlewat socket.sudo mysql - Buat database baru untuk aplikasi.
CREATE DATABASE webapp_db; - Buat account baru khusus untuk koneksi lokal, lengkap dengan password. Ganti nilai password contoh ini dengan password kuat milik sendiri sebelum dipraktikkan di server sungguhan.
CREATE USER 'webapp_user'@'localhost' IDENTIFIED BY 'S4ngatRahasia!2026'; - Berikan seluruh privilege atas database
webapp_dbke account tersebut, lalu terapkan perubahannya.GRANT ALL PRIVILEGES ON webapp_db.* TO 'webapp_user'@'localhost'; FLUSH PRIVILEGES; - Keluar dari sesi
root, lalu uji login dengan account baru.exit mysql -u webapp_user -p webapp_db
Verifikasi dan Troubleshooting
- Login yang berhasil ditandai prompt berubah menjadi
mysql>dengan databasewebapp_dbotomatis terpilih. JalankanSELECT DATABASE(), CURRENT_USER();untuk memastikan sesi benar-benar terhubung sebagaiwebapp_user@localhost. - Perintah
FLUSH PRIVILEGESsebenarnya tidak wajib dijalankan setelahGRANTmaupunCREATE USERdi MySQL 8, karena kedua perintah itu sudah otomatis memperbarui tabel privilege secara langsung. Perintah ini baru benar-benar dibutuhkan saat privilege diubah lewat manipulasi langsung ke tabel sistemmysql.user, kebiasaan lama yang sudah jarang dipakai tetapi masih sering muncul di tutorial karena dianggap kebiasaan aman turun-temurun. - Pesan
ERROR 1045 (28000): Access denied for user 'webapp_user'@'localhost'biasanya berarti password salah ketik, sedangkanERROR 1049 (42000): Unknown database 'webapp_db'menandakan perintahCREATE DATABASEdi langkah sebelumnya belum benar-benar tereksekusi.
19.3.3 Privilege Granular untuk Role Read-Only
Sama seperti kebutuhan tool reporting atau dashboard BI yang sudah dibahas di Bagian 18.3.2, kebutuhan account yang hanya boleh membaca data tanpa bisa mengubahnya juga sering muncul di lingkungan MySQL, biasanya untuk keperluan monitoring atau laporan bisnis yang dikelola tim Developer terpisah dari tim yang menangani data transaksional.
CREATE USER 'webapp_readonly'@'localhost' IDENTIFIED BY 'B4caSaja!2026';
GRANT SELECT ON webapp_db.* TO 'webapp_readonly'@'localhost';Privilege SELECT yang diberikan lewat pola webapp_db.* ini otomatis mencakup seluruh table yang ada di database tersebut, termasuk table yang dibuat setelah perintah GRANT dijalankan, berbeda dari privilege ALL TABLES IN SCHEMA di PostgreSQL yang terbatas pada table yang sudah ada saja. Perbedaan cakupan ini sering jadi jebakan bagi Sysadmin yang terbiasa dengan PostgreSQL lalu berasumsi perilakunya sama persis di MySQL.
Verifikasi dan Troubleshooting
- Perintah
SHOW GRANTS FOR 'webapp_readonly'@'localhost';menampilkan seluruh privilege yang dimiliki account tersebut, cara cepat mengaudit hak akses tanpa perlu membaca ulang riwayat perintahGRANTsebelumnya. - Login sebagai
webapp_readonlylalu mencoba perintahINSERTatauUPDATEharus gagal dengan pesanERROR 1142 (42000): INSERT command denied to user, bukti bahwa privilege granular benar-benar bekerja sesuai rencana.
19.4 Koneksi Remote yang Aman
Sama seperti PostgreSQL di Bagian 18.4, MySQL secara default hanya mendengarkan di alamat loopback, sebuah pilihan keamanan yang disengaja agar server database tidak langsung terekspos ke jaringan begitu instalasi selesai. Membuka akses remote butuh tiga perubahan yang sama persis polanya: mengubah alamat yang didengarkan MySQL, membuat account dengan host yang sesuai, dan mengizinkan traffic-nya di firewall.
19.4.1 Mengaktifkan bind-address dan Firewall
Langkah Praktik
- Buka file konfigurasi utama MySQL, cari directive
bind-addressyang secara default bernilai127.0.0.1.
Ubah baris tersebut agar MySQL mendengarkan di seluruh interface jaringan yang dimiliki server.sudo nano /etc/mysql/mysql.conf.d/mysqld.cnfbind-address = 0.0.0.0 - Directive
bind-addresshanya dibaca saat prosesmysqldpertama kali start, sehingga perubahan ini butuh restart penuh, bukan sekadar reload.sudo systemctl restart mysql - Tambahkan rule UFW yang mengizinkan traffic ke port 3306 khusus dari network lab
192.168.1.0/24, mengikuti pola pembatasan yang sama seperti port 5432 di Bagian 18.4.2.sudo ufw allow from 192.168.1.0/24 to any port 3306 proto tcp
Verifikasi dan Troubleshooting
- Pastikan MySQL benar-benar mendengarkan di semua interface.
Output yang benar menampilkan alamatss -tlnp | grep 33060.0.0.0:3306, bukan127.0.0.1:3306. - Prinsip yang sama seperti catatan Bagian 18.4.1 tetap berlaku di sini: membuka
bind-addresske0.0.0.0lalu membatasi siapa yang benar-benar boleh masuk lewat firewall dan account host tertentu jauh lebih aman dibanding mengekspos port 3306 langsung ke internet publik tanpa pembatasan apa pun.
19.4.2 Membuat Akun untuk Host Remote
Langkah Praktik
- Masuk kembali sebagai
rootlewat socket, lalu buat account baru khusus untuk koneksi dari network lab, terpisah dari'webapp_user'@'localhost'yang sudah ada.sudo mysqlCREATE USER 'webapp_user'@'192.168.1.0/24' IDENTIFIED BY 'S4ngatRahasia!2026'; GRANT ALL PRIVILEGES ON webapp_db.* TO 'webapp_user'@'192.168.1.0/24';
Verifikasi dan Troubleshooting
- Perintah
SELECT user, host FROM mysql.user WHERE user = 'webapp_user';harus menampilkan dua baris,localhostdan192.168.1.0/24, membuktikan keduanya benar-benar dua account terpisah seperti dijelaskan di Bagian 19.3.1.
19.4.3 Menguji Koneksi dari Client Lain di Jaringan
Langkah Praktik
- Dari komputer lain di jaringan lab yang sama, pasang MySQL client saja tanpa server penuhnya.
sudo apt install mysql-client - Coba terhubung ke server database melalui IP
192.168.1.20, memakai account remote yang baru dibuat.mysql -h 192.168.1.20 -u webapp_user -p webapp_db
Verifikasi dan Troubleshooting
- Koneksi yang berhasil akan meminta password lalu menampilkan prompt
mysql>, identik dengan pengujian lewat localhost di Bagian 19.3.2, hanya kali ini benar-benar melewati jaringan. - Pesan
ERROR 2003 (HY000): Can't connect to MySQL server on '192.168.1.20'menandakan MySQL belum mendengarkan di interface jaringan atau firewall masih memblokir port 3306, kembali periksa Bagian 19.4.1. - Pesan
ERROR 1130 (HY000): Host '...' is not allowed to connect to this MySQL servermenandakan alamat IP client tidak cocok dengan host mana pun yang terdaftar dimysql.user, entah karena subnet yang dituliskan salah saatCREATE USERatau client berada di luar range192.168.1.0/24. - Koneksi lewat jaringan lab internal seperti ini masih berupa traffic TCP polos. Secara default, client MySQL modern lebih dulu mencoba menegosiasikan koneksi terenkripsi TLS dan baru turun ke koneksi tanpa enkripsi jika salah satu sisi tidak mendukungnya, perilaku yang dikenal sebagai mode
PREFERRED. Mewajibkan enkripsi penuh tanpa opsi turun ke plaintext berarti mengaktifkanREQUIRE SSLsecara eksplisit pada account yang bersangkutan, atau menyalakan system variablerequire_secure_transportdi level server untuk memblokir seluruh koneksi TCP tanpa TLS.
19.5 Catatan Migrasi MySQL 8.0 ke 8.4
MySQL 8.0 dirilis pertama kali pada 2018 dan bertahan sebagai versi utama selama bertahun-tahun lewat rangkaian update minor. Oracle kemudian mengubah total strategi rilisnya mulai MySQL 8.4: Innovation release dirilis tiap sekitar tiga bulan membawa fitur baru tetapi hanya didukung sampai rilis Innovation berikutnya, sedangkan Long Term Support (LTS) seperti 8.4 dirilis lebih jarang namun mendapat dukungan keamanan selama beberapa tahun penuh, model yang cukup mirip filosofi LTS pada Ubuntu sendiri. MySQL 8.4 menjadi rilis LTS pertama di bawah model baru ini, sekaligus menjadi versi yang dipaketkan Ubuntu 26.04 seperti sudah kita instal di Bagian 19.2.
Beberapa perubahan penting yang perlu diwaspadai Sysadmin saat memigrasikan aplikasi lama dari MySQL 8.0 ke 8.4 antara lain.
- Plugin
mysql_native_passwordtidak lagi dimuat secara default. Aplikasi lama atau driver database versi lawas yang masih mengandalkan metode autentikasi ini bisa gagal connect setelah migrasi, kecuali plugin-nya diaktifkan ulang secara eksplisit atau account yang bersangkutan dimigrasikan kecaching_sha2_password, plugin yang sudah kita pakai secara default sejak instalasi di Bagian 19.2. - Sejumlah system variable dihapus, termasuk
innodb_log_file_sizedaninnodb_log_files_in_groupyang digantikan satu variable baru bernamainnodb_redo_log_capacity, serta seluruh variable berawalanslave_*yang digantikan padananreplica_*, konsisten dengan upaya Oracle mengganti terminologi replikasi lama di seluruh dokumentasi MySQL modern. - Sisa system variable query cache akhirnya benar-benar dihapus. Fitur query cache itu sendiri sudah dihilangkan total sejak MySQL 8.0, tetapi sejumlah variable peninggalannya seperti
query_cache_sizedanquery_cache_typemasih dipertahankan sebagai pengaturan tanpa efek supaya file konfigurasi lama tidak langsung gagal dibaca. MySQL 8.4 akhirnya menghapus variable peninggalan ini sepenuhnya, sehingga konfigurasi lama yang masih menyebutnya harus dibersihkan darimy.cnfsebelum upgrade, karena MySQL akan menolak start jika menemukan variable yang sudah tidak dikenali sama sekali.
Jalur upgrade yang direkomendasikan Oracle adalah in-place upgrade lewat mekanisme APT biasa untuk server yang sudah menjalankan MySQL 8.0 versi minor terbaru, bukan dump-restore penuh. Sysadmin tetap wajib membaca release notes resmi dan, yang jauh lebih penting, mencoba upgrade lebih dulu di server staging sebelum menyentuh server production, mengikuti prinsip kehati-hatian yang sama seperti setiap perubahan berisiko lain yang sudah kita praktikkan sepanjang series ini.
Verifikasi versi yang sedang berjalan cukup dilakukan lewat client MySQL, cara paling sederhana untuk memastikan server benar-benar sudah berada di versi yang diharapkan setelah proses upgrade selesai.
mysql -u root -p -e "SELECT VERSION();"Sampai di sini, server sudah menjalankan MySQL 8.4 lengkap dengan database webapp_db yang dimiliki account aplikasi tersendiri, terpisah dari root yang terkunci lewat auth_socket, dan bisa diakses dengan aman dari jaringan lab lewat kombinasi account berbasis host serta firewall yang dibatasi ketat. Bab 20 melanjutkan Bagian V dengan RDBMS ketiga, MariaDB, RDBMS hasil fork yang baru saja kita bahas sejarahnya, sekaligus menjadi pilihan default modern Ubuntu untuk kebutuhan yang sama.

