Moving the MySQL or MariaDB data directory to a dedicated filesystem can free space on the root volume, put database files on faster storage, and simplify backup or snapshot planning when database growth no longer fits comfortably under /var.
On Ubuntu, both database servers can read the datadir setting from option files under /etc/mysql and then let systemd start the daemon against that location. A safe move therefore means stopping the service, copying the full contents with ownership and permissions intact, adding or changing the active server option, and keeping the old directory as rollback until startup succeeds.
The package details differ on current Ubuntu releases. MySQL uses /etc/mysql/mysql.conf.d/mysqld.cnf and ships the /etc/apparmor.d/usr.sbin.mysqld profile, while MariaDB uses /etc/mysql/mariadb.conf.d/50-server.cnf and recent Ubuntu packages may report /var/lib/mariadb instead of /var/lib/mysql as the starting directory. If the new path lives on a separate filesystem, make sure it is mounted before the service starts, because a missing mount can expose an empty directory at the same path and cause the move to fail or start against the wrong files.
$ sudo mysql --table --execute "SHOW VARIABLES LIKE 'datadir';" +---------------+----------------+ | Variable_name | Value | +---------------+----------------+ | datadir | /var/lib/mysql/| +---------------+----------------+
Add --user=root --password when local administrative access is not configured for sudo mysql. Current Ubuntu MariaDB packages may return /var/lib/mariadb/ instead; use the value shown by this query anywhere the steps refer to /var/lib/mysql.
$ systemctl status mysql --no-pager
● mysql.service - MySQL Community Server
Loaded: loaded (/usr/lib/systemd/system/mysql.service; enabled; preset: enabled)
Active: active (running)
Current Ubuntu MariaDB packages usually keep mysql.service as a compatibility alias even though mariadb.service is the primary unit name. Use mariadb in the service commands only when mysql does not resolve on the host.
Related: How to manage MySQL or MariaDB service with systemctl in Linux
$ sudo systemctl stop mysql
Stopping the service drops active connections, so schedule the move for a maintenance window or application outage.
$ sudo install --directory --owner=mysql --group=mysql --mode=0750 /data/mysql
The target filesystem needs normal Linux ownership and permission support, such as ext4 or xfs.
$ df -h /data/mysql Filesystem Size Used Avail Use% Mounted on /dev/sdb1 200G 20G 170G 11% /data
Do not start the service until the real mounted filesystem is present at the new path. A missing mount can hide the copied files, and current MySQL packages on systemd can initialize an empty data directory when startup sees an empty target path.
$ sudo cp --archive /var/lib/mysql/. /data/mysql/
Replace /var/lib/mysql with the path returned by the earlier datadir query when it differs from the example.
$ sudo stat --format "%U:%G %a %n" /data/mysql mysql:mysql 750 /data/mysql
$ sudo mv /var/lib/mysql /var/lib/mysql.old
Keep the rollback copy until the service starts cleanly and the server reports the new datadir. If the original query returned /var/lib/mariadb/, rename that directory to /var/lib/mariadb.old instead.
$ ls /etc/mysql/mysql.conf.d/mysqld.cnf /etc/mysql/mariadb.conf.d/50-server.cnf 2>/dev/null /etc/mysql/mysql.conf.d/mysqld.cnf
Use /etc/mysql/mysql.conf.d/mysqld.cnf for MySQL and /etc/mysql/mariadb.conf.d/50-server.cnf for MariaDB. Current packages may leave the packaged datadir example commented, so an empty search result for an active datadir line does not mean the wrong file was selected.
Related: How to locate and modify MySQL and MariaDB configuration files
$ sudoedit /etc/mysql/mysql.conf.d/mysqld.cnf
[mysqld] datadir = /data/mysql
For MariaDB in /etc/mysql/mariadb.conf.d/50-server.cnf, add the same setting under [mariadbd]. If a commented datadir line already exists, uncomment and change that line instead of adding a duplicate later in the same section.
$ my_print_defaults mysqld --user=mysql --datadir=/data/mysql --bind-address=127.0.0.1 ##### snipped #####
If more than one --datadir line appears, another later option file is still overriding the setting. For MariaDB, run my_print_defaults mariadbd server instead.
$ sudo ls /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/usr.sbin.mysqld
Current Ubuntu MySQL packages install this profile. Some current Ubuntu MariaDB package installs do not ship /etc/apparmor.d/usr.sbin.mariadbd; skip the AppArmor edit and reload steps when no matching database profile exists.
$ sudoedit /etc/apparmor.d/local/usr.sbin.mysqld
Use /etc/apparmor.d/local/usr.sbin.mariadbd instead when /etc/apparmor.d/usr.sbin.mariadbd exists on a MariaDB host.
/data/mysql/ r, /data/mysql/** rwk,
The packaged MySQL profile includes the matching local file, so this keeps the path change separate from package-owned AppArmor rules.
$ sudo apparmor_parser --replace /etc/apparmor.d/usr.sbin.mysqld
Replace the profile path with /etc/apparmor.d/usr.sbin.mariadbd when that is the file detected on the host.
$ sudo systemctl start mysql
Replace mysql with mariadb when the host does not expose the mysql.service compatibility alias.
$ systemctl is-active mysql active
Replace mysql with mariadb when the host does not expose the mysql.service compatibility alias.
$ sudo mysql --table --execute "SHOW VARIABLES LIKE 'datadir';" +---------------+-------------+ | Variable_name | Value | +---------------+-------------+ | datadir | /data/mysql/| +---------------+-------------+
$ sudo journalctl --unit=mysql --no-pager --since "10 minutes ago" ##### snipped ##### apparmor="DENIED" operation="open" profile="usr.sbin.mysqld" name="/data/mysql/ibdata1" pid=12345 comm="mysqld" ##### snipped #####
Replace mysql with mariadb when the host does not expose the mysql.service compatibility alias.
Related: How to view the MySQL or MariaDB server error log
Related: How to disable and remove AppArmor in Ubuntu and Debian
$ sudo rm --recursive --force /var/lib/mysql.old
Deleting the rollback directory is irreversible, so keep a verified backup before running rm. Remove /var/lib/mariadb.old instead when that was the original data directory.