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 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, pointing the active server option file at the new path, and keeping the old directory as rollback until startup succeeds.

The package details differ slightly on current Ubuntu releases: MySQL uses /etc/mysql/mysql.conf.d/mysqld.cnf with the AppArmor profile /etc/apparmor.d/usr.sbin.mysqld, while MariaDB uses /etc/mysql/mariadb.conf.d/50-server.cnf with /etc/apparmor.d/usr.sbin.mariadbd. 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, on current MySQL packages, initialize a fresh empty data directory.

Steps to change MySQL or MariaDB data directory in Ubuntu:

  1. Record the current datadir value from the running server.
    $ 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.

  2. Identify the database service unit that the host actually uses.
    $ systemctl list-unit-files --type=service | grep --extended-regexp '^(mysql|mariadb)\.service'
    mysql.service                                enabled         enabled

    Current Ubuntu MariaDB packages usually keep mysql.service as a compatibility alias even though mariadb.service is the primary unit name, so use the name that resolves correctly on the host.
    Related: How to manage MySQL or MariaDB service in Linux

  3. Stop the database service before copying any files.
    $ sudo systemctl stop mysql

    Stopping the service drops active connections, so schedule the move for a maintenance window or application outage.

  4. Create the new data directory with the expected owner, group, and mode.
    $ 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.

  5. Confirm that the new path is already on the intended mounted filesystem.
    $ 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.

  6. Copy the existing database files to the new path with metadata preserved.
    $ 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 default.

  7. Verify the copied directory still belongs to the mysql service account.
    $ sudo stat --format "%U:%G %a %n" /data/mysql
    mysql:mysql 750 /data/mysql
  8. Rename the original data directory so it remains available for rollback.
    $ 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.

  9. Locate the option file that currently defines datadir on this host.
    $ sudo grep --recursive --line-number --extended-regexp '^[[:space:]]*datadir[[:space:]]*=' /etc/mysql/
    /etc/mysql/mysql.conf.d/mysqld.cnf:31:datadir = /var/lib/mysql

    Current Ubuntu MySQL packages usually store this in /etc/mysql/mysql.conf.d/mysqld.cnf, while current MariaDB packages usually use /etc/mysql/mariadb.conf.d/50-server.cnf.
    Related: How to locate and modify MySQL and MariaDB configuration files

  10. Open the file that contains the active datadir setting.
    $ sudoedit /etc/mysql/mysql.conf.d/mysqld.cnf

    Use the exact file returned by the previous command instead of editing every file under /etc/mysql.

  11. Update the datadir setting under [mysqld] to the new path.
    [mysqld]
    datadir = /data/mysql
  12. Confirm the effective server options now point at the new datadir before startup.
    $ my_print_defaults mysqld | grep '^--datadir='
    --datadir=/data/mysql

    If more than one --datadir line appears, another later option file is still overriding the setting.

  13. Open the AppArmor alias file used for site-specific path remapping.
    $ sudoedit /etc/apparmor.d/tunables/alias
  14. Add an alias that maps the default data directory to the new path.
    alias /var/lib/mysql/ -> /data/mysql/,

    The alias lets the packaged AppArmor profile keep referring to /var/lib/mysql while granting access to the new directory.

  15. Identify the AppArmor database profile file installed by the current package.
    $ ls /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/usr.sbin.mariadbd 2>/dev/null
    /etc/apparmor.d/usr.sbin.mysqld

    Current Ubuntu MySQL packages use usr.sbin.mysqld, while current MariaDB packages use usr.sbin.mariadbd.

  16. Reload the matching AppArmor profile after the alias change.
    $ 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.

  17. Start the database service against the new data directory.
    $ sudo systemctl start mysql

    Replace mysql with mariadb when the host does not expose the mysql.service compatibility alias.

  18. Confirm that the service returned to the active state.
    $ systemctl is-active mysql
    active

    Replace mysql with mariadb when the host does not expose the mysql.service compatibility alias.

  19. Verify that the live server now reports the new data directory.
    $ sudo mysql --table --execute "SHOW VARIABLES LIKE 'datadir';"
    +---------------+-------------+
    | Variable_name | Value       |
    +---------------+-------------+
    | datadir       | /data/mysql/|
    +---------------+-------------+
  20. Review the recent journal if startup fails or AppArmor denies the new path.
    $ 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

  21. Remove the rollback copy only after normal database access has been confirmed from the new location.
    $ sudo rm --recursive --force /var/lib/mysql.old

    Deleting the rollback directory is irreversible, so keep a verified backup before running rm.