Databases Azure

MySQL Router 8.4 on Ubuntu 24.04 LTS | cloudimg

| Product: mysql-router

MySQL Router 8.4 on Ubuntu 24.04 LTS

MySQL Router is Oracle's official lightweight connection proxy for MySQL. It presents applications with a single stable endpoint and transparently routes each connection to a healthy backend — the standard connection tier in front of a MySQL InnoDB Cluster or replica set.

This cloudimg image installs MySQL Router 8.4 from Oracle's official APT repository onto Ubuntu 24.04 LTS (Noble Numbat), together with a bundled MySQL 8.4 LTS Community server as a default backend, so the appliance routes live traffic the moment it boots. A unique MySQL root password and a unique application-user password are generated automatically on first boot — no credential is baked into the image.

Topology

The image ships a self-contained routing tier you can use immediately and re-point at your own database in production:

Listener Port Bind Routes to
Classic protocol, read/write 6446 0.0.0.0 MySQL 127.0.0.1:3306
Classic protocol, read-only 6447 0.0.0.0 MySQL 127.0.0.1:3306
X protocol, read/write 6448 0.0.0.0 MySQL 127.0.0.1:33060
X protocol, read-only 6449 0.0.0.0 MySQL 127.0.0.1:33060

The bundled MySQL server is bound to loopback (127.0.0.1) and is reachable only through the router. MySQL authentication (a per-VM password, no anonymous login) is the security gate. In production you point the router at your own MySQL server or InnoDB Cluster — a configuration change, not a boot dependency.

Prerequisites

  • An Azure subscription with permission to create virtual machines
  • An SSH key pair — the public key is uploaded during VM creation
  • A MySQL client installed locally if you want to connect from your workstation

Step 1 — Deploy from the Azure Portal

  1. Find MySQL Router 8.4 on Ubuntu 24.04 by cloudimg in the Azure Marketplace and click Create.
  2. On the Basics tab, select or create a Resource Group, choose East US as the region, and set the VM size to Standard_B2s (2 vCPU / 4 GB RAM) or larger.
  3. Under Administrator account, choose SSH public key and paste your public key.
  4. On the Networking tab, open the router ports you intend to use — 6446 (read/write) and 6447 (read-only) for the classic protocol, plus 6448/6449 for the X protocol — in addition to 22 (SSH). Restrict the source to your application subnet.
  5. Click Review + create, then Create.

Step 2 — Deploy with the Azure CLI

az vm create \
  --resource-group <your-resource-group> \
  --name mysql-router \
  --image "$(az sig image-version list \
       --resource-group AZURE-CLOUDIMG \
       --gallery-name cloudimgGallery \
       --gallery-image-definition mysql-router \
       --query '[0].id' -o tsv)" \
  --size Standard_B2s \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_rsa.pub \
  --public-ip-sku Standard

After the VM starts, open the router read/write port:

az vm open-port --port 6446 --resource-group <your-resource-group> --name mysql-router

Step 3 — Connect via SSH

ssh azureuser@<vm-ip>

On first boot, mysql-router-firstboot.service starts the backend MySQL server, generates the per-VM root and application passwords, creates the default cloudimg database and cloudimg_app user, and starts MySQL Router. Allow 30–60 seconds for the service to complete before connecting.

Step 4 — Retrieve Your Credentials

sudo cat /stage/scripts/mysql-router-credentials.log

The file is owned root:root (mode 0600) and lists the generated passwords, the router ports, and ready-to-use connect commands. Store the passwords somewhere safe before you rotate them.

The per-VM MySQL root and application credentials generated on first boot, with secrets masked

Step 5 — Verify the Routing Topology

Confirm both services are healthy and inspect the listening ports — the router is on 0.0.0.0, the backend MySQL is loopback-only:

systemctl is-active mysql mysqlrouter
sudo ss -tlnp | grep -E ':(3306|33060|6446|6447|6448|6449) '

MySQL Router and the backend MySQL server healthy under systemd, router listening on 6446-6449 and MySQL bound to 127.0.0.1

Step 6 — Connect Through the Router

Connect to the router read/write port (6446) using the generated application password, write a sentinel row, and read it back. The row records the backend port the connection actually reached — proving the traffic traversed the router:

APP_USER=$(sudo awk -F= '/^app_user=/{print $2}' /stage/scripts/mysql-router-credentials.log)
APP_PASS=$(sudo awk -F= '/^app_password=/{print $2}' /stage/scripts/mysql-router-credentials.log)
MYSQL_PWD="$APP_PASS" mysql -u "$APP_USER" -h 127.0.0.1 -P 6446 cloudimg --table <<'SQL'
CREATE TABLE IF NOT EXISTS demo (id INT PRIMARY KEY AUTO_INCREMENT, note VARCHAR(64), via_port INT, backend_port INT);
INSERT INTO demo (note, via_port, backend_port) VALUES ('hello via router', 6446, @@port);
SELECT note, via_port AS connected_to_router_port, backend_port AS mysql_server_port FROM demo ORDER BY id DESC LIMIT 1;
SQL

You connected to the router on 6446, but the backend reports its port as 3306 — the connection was routed through MySQL Router to the MySQL server behind it.

A client connecting through MySQL Router on port 6446, with the routed write reaching the backend MySQL server on port 3306

Step 7 — Use the Read-Only Port and Inspect the Router Log

Read the same data back over the router's read-only port (6447), then confirm the router logged that it is accepting connections on each routing port:

APP_USER=$(sudo awk -F= '/^app_user=/{print $2}' /stage/scripts/mysql-router-credentials.log)
APP_PASS=$(sudo awk -F= '/^app_password=/{print $2}' /stage/scripts/mysql-router-credentials.log)
MYSQL_PWD="$APP_PASS" mysql -u "$APP_USER" -h 127.0.0.1 -P 6447 cloudimg --table \
  -e "SELECT note, via_port, backend_port FROM demo ORDER BY id DESC LIMIT 3;"
sudo grep 'Start accepting' /var/log/mysqlrouter/mysqlrouter.log | tail -4

Reading data back through the router read-only port 6447 and the MySQL Router log showing it accepting connections on each routing port

Step 8 — Point the Router at Your Own MySQL or InnoDB Cluster

In production the router fronts your database. Edit the destinations in /etc/mysqlrouter/mysqlrouter.conf and restart the service. For a single server, change the destinations lines to your host:

sudo sed -i 's#destinations=127.0.0.1:3306#destinations=<your-mysql-host>:3306#' /etc/mysqlrouter/mysqlrouter.conf
sudo sed -i 's#destinations=127.0.0.1:33060#destinations=<your-mysql-host>:33060#' /etc/mysqlrouter/mysqlrouter.conf
sudo systemctl restart mysqlrouter

For a MySQL InnoDB Cluster, re-bootstrap the router against the cluster so it tracks membership and failover automatically (this rewrites mysqlrouter.conf with a metadata cache):

sudo mysqlrouter --bootstrap <cluster-admin>@<your-mysql-host>:3306 \
  --user mysqlrouter --force
sudo systemctl restart mysqlrouter

Step 9 — Service Management

sudo systemctl status mysqlrouter --no-pager
sudo /usr/local/sbin/mysql-router-status.sh
sudo journalctl -u mysqlrouter -n 50 --no-pager

Step 10 — Security Recommendations

  • Point the router at your own MySQL server or InnoDB Cluster (Step 8) and keep the bundled backend for evaluation only, or repurpose it as a production node.
  • Open only the router ports your applications need (6446/6447 for classic, 6448/6449 for X protocol), and restrict the NSG source to your application subnet.
  • Rotate the generated application password and create least-privilege users for each application:
ROOT_PASS=$(sudo awk -F= '/^root_password=/{print $2}' /stage/scripts/mysql-router-credentials.log)
mysql -u root --password="${ROOT_PASS}" --socket=/var/run/mysqld/mysqld.sock <<SQL
ALTER USER 'cloudimg_app'@'%' IDENTIFIED WITH caching_sha2_password BY '<new-password>';
FLUSH PRIVILEGES;
SQL
  • Keep the system patched: sudo apt-get update && sudo apt-get upgrade -y.

Troubleshooting

Router not accepting connections — confirm it is listening and check the log:

sudo ss -tlnp | grep 6446
sudo tail -n 50 /var/log/mysqlrouter/mysqlrouter.log

Backend unreachable — the router starts even when its destination is down and returns errors to clients until the backend is up. Confirm the backend MySQL server is running and reachable from the router host:

sudo systemctl status mysql --no-pager

Support

This image is provided and supported by cloudimg. For deployment questions, configuration assistance, or bug reports, contact us at support@cloudimg.co.uk.

For upstream documentation, see the MySQL Router 8.4 Reference.