MySQL 9 on Rocky 9
Overview
This guide covers deploying and configuring MySQL 9 Community Server (version 9.6.0, Innovation track) on Rocky Linux 9 on Microsoft Azure, using SecureAnyCloud's pre-configured virtual machine image from the Azure Marketplace. MySQL 9 brings new SQL features, native vector data types for AI workloads, and continuing support for the InnoDB storage engine.
The image ships with MySQL 9 pre-installed, a production default configuration, and a first-boot service that rotates the root password to a per-VM unique value on the first customer boot.
What you get:
- MySQL 9.6.0 Community Server from the official Oracle MySQL Innovation channel for el9.
- A production default configuration at
/etc/my.cnf.d/sac.cnf: utf8mb4 default, 512M InnoDB buffer pool, slow query log on, max_connections 200. - Per-VM root password rotation by
mysql-firstboot.serviceon first boot. - A default SecureAnyCloud database (utf8mb4_0900_ai_ci), ready for customer use.
mysqld.serviceenabled for boot start.- Logs at
/var/log/mysql/error.logand/var/log/mysql/slow.log. - Latest security patches applied at build time.
- Platform: Microsoft Azure (Gen2 Hyper-V). Default OS user:
azureuser.
Deploy the Virtual Machine
az vm image terms accept --urn sac1647283583153:mysql-9-rocky-9:default:latest
az vm create -g <resource-group> -n mysql-9-vm -l eastus \
--image sac1647283583153:mysql-9-rocky-9:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_rsa.pubFor higher-load workloads, choose a memory-optimized SKU such as Standard_E4s_v5 (4 vCPU, 32 GB RAM). Tune innodb_buffer_pool_size after first boot, as described in Step 10.
Connect via SSH
ssh azureuser@<public-ip>Confirm the OS:
cat /etc/rocky-releaseConfirm MySQL is Running
mysqld.service starts automatically at boot.
sudo systemctl is-active mysqld.serviceShow full status:
sudo systemctl status mysqld.service --no-pager | head -12Locate the Per-VM Root Password
On first boot, mysql-firstboot.service rotates the root password and writes the new credentials to /home/azureuser/CREDENTIALS.txt. Display the file:
sudo cat /home/azureuser/CREDENTIALS.txtThe file is owned by root:root with mode 0600. It contains the per-VM password, the default database name and the path to your config file. Copy the password to a secure location, then remove the file.
Confirm MySQL is Listening
sudo ss -tlnp | grep ':3306'Connect with the MySQL Client
Run a one-shot version check using the password that first boot rotated:
sudo mysql -uroot -p$(grep '^Password:' /home/azureuser/CREDENTIALS.txt | awk '{print $2}') -e "SELECT VERSION(), NOW()"For an interactive session:
mysql -uroot -pCheck server uptime and the schemas shipped with the image:
sudo bash -c 'PASS=$(grep "^Password:" /home/azureuser/CREDENTIALS.txt | awk "{print \$2}"); mysqladmin -uroot -p"$PASS" status; mysql -uroot -p"$PASS" --table -e "SHOW DATABASES;"'Create an Application Database and User
The default SecureAnyCloud database is fine for testing. For production, create a dedicated database and a least-privilege user instead of connecting as root. Set the password to a strong value of your own choice:
sudo mysql -uroot -p$(grep '^Password:' /home/azureuser/CREDENTIALS.txt | awk '{print $2}') <<'SQL' CREATE DATABASE IF NOT EXISTS appdb CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; CREATE USER IF NOT EXISTS 'appuser'@'%' IDENTIFIED BY 'CHANGE_ME_StrongPasswordExample123!'; GRANT ALL PRIVILEGES ON appdb.* TO 'appuser'@'%'; FLUSH PRIVILEGES; SHOW GRANTS FOR 'appuser'@'%'; SQLFor a localhost-only user, which is more secure if your application runs on the same VM, replace 'appuser'@'%' with 'appuser'@'localhost'.
A round-trip CREATE / INSERT / SELECT against the default SecureAnyCloud database looks like this:
Open Azure NSG for Port 3306 (Remote Connections)
Rocky Linux 9 ships with firewalld, but the SecureAnyCloud image leaves it inactive. The network boundary is the Azure NSG. Open port 3306 from your application VNet only, and never from 0.0.0.0/0 in production:
az network nsg rule create -g <resource-group> --nsg-name <nsg-name> \
-n allow-mysql-3306 \
--priority 200 \
--direction Inbound \
--access Allow \
--protocol Tcp \
--source-address-prefixes 10.0.0.0/16 \
--destination-port-ranges 3306Replace 10.0.0.0/16 with your application subnet's CIDR. Then test from a client machine on that VNet:
mysql -h <vm-private-ip> -P 3306 -u appuser -pBackup and Restore
Create a logical dump of a single database:
sudo mysqldump -uroot -p$(grep '^Password:' /home/azureuser/CREDENTIALS.txt | awk '{print $2}') \
--single-transaction --routines --triggers --events \
sac > /home/azureuser/sac-$(date +%Y%m%d).sqlOr back up everything. Use --all-databases for a full server snapshot:
sudo mysqldump -uroot -p$(grep '^Password:' /home/azureuser/CREDENTIALS.txt | awk '{print $2}') \
--all-databases --single-transaction --routines --triggers --events \
> /home/azureuser/full-$(date +%Y%m%d).sqlRestore a dump into a target database:
sudo mysql -uroot -p$(grep '^Password:' /home/azureuser/CREDENTIALS.txt | awk '{print $2}') sac < /home/azureuser/sac-20260517.sqlFor routine production backups, schedule the dump with cron and copy it to Azure Blob Storage or an Azure Files share.
Tuning InnoDB Buffer Pool for Larger VMs
SecureAnyCloud defaults innodb_buffer_pool_size to 512 MB so that MySQL fits comfortably on the Standard_B2s build target (4 GB RAM total). On a larger VM, allocate roughly 50 to 70 percent of system RAM to the buffer pool. For example, on a Standard_E4s_v5 (32 GB RAM):
Add a customer override file at /etc/my.cnf.d/local.cnf. It loads after sac.cnf, so its values win. Replace <buffer-pool-size> with a value appropriate to your VM RAM (for example, 16G on Standard_E4s_v5):
sudo tee /etc/my.cnf.d/local.cnf >/dev/null <<CNF [mysqld] innodb_buffer_pool_size = <buffer-pool-size> innodb_buffer_pool_instances = 8 innodb_log_file_size = 1G max_connections = 500 CNF
sudo systemctl restart mysqld.serviceConfirm the new value is applied:
sudo mysql -uroot -p$(grep '^Password:' /home/azureuser/CREDENTIALS.txt | awk '{print $2}') -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size'"The local override survives package upgrades. sac.cnf does not regenerate on package upgrade, but if you need to change shipped defaults, always do it in local.cnf rather than editing sac.cnf in place.
Slow Query Analysis
SecureAnyCloud enables the slow query log out of the box at /var/log/mysql/slow.log, with a 2-second threshold. Generate some load, then inspect the log:
sudo tail -30 /var/log/mysql/slow.log 2>/dev/null || echo "no slow queries logged yet"Use the bundled mysqldumpslow to summarize the top offenders by total time:
sudo mysqldumpslow -s t /var/log/mysql/slow.log 2>/dev/null | head -30 || echo "no slow queries"To lower the threshold temporarily for debugging, run the following. No restart is needed:
sudo mysql -uroot -p$(grep '^Password:' /home/azureuser/CREDENTIALS.txt | awk '{print $2}') -e "SET GLOBAL long_query_time = 0.5"When you finish debugging, set the threshold back with SET GLOBAL long_query_time = 2.
SSL/TLS Connections
MySQL 9 generates self-signed SSL certificates automatically on first initialization. Verify that they are in place and that the server accepts TLS connections:
sudo ls -la /var/lib/mysql/*.pem
sudo mysql -uroot -p$(grep '^Password:' /home/azureuser/CREDENTIALS.txt | awk '{print $2}') -e "SHOW VARIABLES LIKE 'have_ssl'"Require a single user to connect over TLS only. This applies once appuser exists (see Step 7):
sudo mysql -uroot -p$(grep '^Password:' /home/azureuser/CREDENTIALS.txt | awk '{print $2}') -e "ALTER USER 'appuser'@'%' REQUIRE SSL"For production, replace the auto-generated certificates with ones from Azure Key Vault or Let's Encrypt. Point ssl-cert, ssl-key and ssl-ca in /etc/my.cnf.d/local.cnf at the new files.
Managing the Server
Restart MySQL:
sudo systemctl restart mysqld.serviceTail the error log:
sudo tail -20 /var/log/mysql/error.log 2>/dev/null || echo "no error log file yet — startup events are in journalctl -u mysqld"Check open connections:
sudo mysql -uroot -p$(grep '^Password:' /home/azureuser/CREDENTIALS.txt | awk '{print $2}') -e "SHOW PROCESSLIST"Updating MySQL Within the 9.x Innovation Channel
The image ships with mysql-innovation-community enabled and mysql-8.4-lts-community disabled. Apply minor 9.x updates as Oracle releases them:
sudo dnf upgrade -y --nogpgcheck mysql-community-server mysql-community-client
sudo systemctl restart mysqld.service mysqld --versionNote: the MySQL signing key (B7B3B788A8D3785C) expired on 2025-10-22, but Oracle continues to sign 9.x RPMs with it. The --nogpgcheck flag is required until Oracle publishes a 2026 replacement key. On dnf5, you may also need dnf download --resolve plus rpm -ivh --nosignature --nodigest.
Common Errors
"Access denied for user 'root'@'localhost' (using password: NO)". First boot rotated the password. Read it again from /home/azureuser/CREDENTIALS.txt.
"Can't connect to MySQL server on '\<vm-ip>:3306'". The Azure NSG is blocking the port. See Step 8.
"Too many connections". Raise max_connections in /etc/my.cnf.d/local.cnf and restart MySQL.
"[Warning] Using a password on the command line interface can be insecure". MySQL emits this warning whenever a password is given on the command line. For automation, put the password in ~/.my.cnf with mode 0600 and call mysql --defaults-file=~/.my.cnf instead.
"InnoDB: Cannot allocate memory for the buffer pool". Your VM does not have enough RAM for the configured innodb_buffer_pool_size. Lower it in /etc/my.cnf.d/local.cnf, or move to a larger SKU.
On Startup
mysqld.service is enabled at boot via systemd:
sudo systemctl is-enabled mysqld.servicemysql-firstboot.service runs once, on the first customer boot, to rotate the root password. It then stays in the active (exited) state and does nothing on later reboots.
Support
SecureAnyCloud provides 24/7 expert support for this image. Contact sales@secureanycloud.com.
License: MySQL Community Server is licensed under GPLv2. SecureAnyCloud charges a per-vCPU, per-hour fee for packaging, security patching, and 24/7 support.
MySQL is a registered trademark of Oracle Corporation. Rocky Linux is a registered trademark of the Rocky Enterprise Software Foundation.
Deploy on Azure
Launch MySQL 9 Community Server on Rocky Linux 9 on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com