Databases grow over time, sometimes outgrowing the space on the file system. You can also run into input/output (I/O) contention when they’re located on the same partition as the rest of the operating system. Redundant Array of Independent Disks (RAID), network block storage, and other devices, can offer redundancy and other desirable features. Whether you’re adding more space, evaluating ways to optimize performance, or wanting to take advantage of other storage features, this tutorial will guide you through relocating MySQL’s data directory.
To complete this guide, you will need:
An Ubuntu 20.04 server with a non-root user with sudo
privileges and a firewall enabled. You can learn more about how to set up a user with these privileges in our Initial Server Setup with Ubuntu 20.04 guide.
A MySQL server. If you haven’t already installed MySQL, check out our guide on How To Install MySQL on Ubuntu 20.04.
In this tutorial, we’re moving the data to a block storage device mounted at /mnt/volume-nyc1-01
. You can learn how to set one up in the following documentation on Block Storage Volumes on DigitalOcean.
No matter what underlying storage you use, this guide can help you move the data directory to a new location.
To prepare for moving MySQL’s data directory, let’s verify the current location by starting an interactive MySQL session using the administrative credentials. Run the following command to open the MySQL server prompt:
- sudo mysql
Note: If you configured your root MySQL user to authenticate using a password, you can connect to MySQL as this user with the following command:
- mysql -u root -p
When prompted, supply the MySQL user password. Then from the MySQL prompt, run the following SELECT
statement. This will return this MySQL instance’s active data directory, which is always recorded in MySQL’s datadir
variable::
- SELECT @@datadir;
Output+-----------------+
| @@datadir |
+-----------------+
| /var/lib/mysql/ |
+-----------------+
1 row in set (0.00 sec)
This output confirms that MySQL is configured to use the default data directory, /var/lib/mysql/
, so that’s the directory you need to move. Once you’ve confirmed this, write exit
to leave the monitor and return to your command prompt:
- exit
OutputBye
To ensure the integrity of the data, shut down MySQL before making changes to the data directory:
- sudo systemctl stop mysql
Note that systemctl
doesn’t display the outcome of all service management commands, so if you want to check if you’ve succeeded, use the following command:
- sudo systemctl status mysql
You can confirm it’s shut down if the Active
line in the output states it’s inactive (dead)
as highlighted in the following example:
Output● mysql.service - MySQL Community Server
Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset:>
Active: inactive (dead) since Wed 2022-03-23 19:03:49 UTC; 5s ago
Process: 3415 ExecStart=/usr/sbin/mysqld (code=exited, status=0/SUCCESS)
Main PID: 3415 (code=exited, status=0/SUCCESS)
Status: "Server shutdown complete"
Now that the server is shut down, you can copy the existing database directory, /var/lib/mysql
, to the new location, /mnt/volume-nyc1-01
, with rsync
. Using the -a
flag preserves the permissions and other directory properties, while-v
provides verbose output so you can follow the progress:
Note: Be sure there is no trailing slash on the directory, which may be added if you use tab completion. When there’s a trailing slash, rsync
will dump the contents of the directory into the mount point instead of transferring it into a containing mysql
directory.
- sudo rsync -av /var/lib/mysql /mnt/volume-nyc1-01
Once the rsync
command is complete, rename the current folder with a .bak
extension and keep it until you’ve confirmed the move was successful. By renaming it, you’ll avoid confusion that could arise from files in both the new and the old location:
- sudo mv /var/lib/mysql /var/lib/mysql.bak
Now you’re ready to proceed with the next step and begin configuration.
MySQL has several ways to override configuration values. By default, the datadir
is set to /var/lib/mysql
in the /etc/mysql/mysql.conf.d/mysqld.cnf
file. Edit this file in your preferred text editor to reflect the new data directory. Here we’ll use nano
:
- sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
Find the line that begins with datadir=
. Uncomment the line by deleting the pound sign (#
) and change the path to reflect the new location. In this case, the updated file contents will be as follows:
. . .
datadir=/mnt/volume-nyc1-01/mysql
. . .
Once you’ve made this update, save and exit the file. If you’re using nano
, you can do this by pressing CTRL + X
, then Y
, and ENTER
. Now it’s almost time to bring up MySQL again, but before that, there’s one more thing to configure in order to be successful.
In this step, you need to tell AppArmor to let MySQL write to the new directory by creating an alias between the default directory and the new location. AppArmor is a security module in the Linux kernel that allows system administrators to restrict program capabilities through program profiles, rather than users themselves. Start by opening up and editing the AppArmor alias
file:
- sudo nano /etc/apparmor.d/tunables/alias
At the bottom of the file, uncomment the following line and add the alias rule:
. . .
alias /var/lib/mysql/ -> /mnt/volume-nyc1-01/mysql/,
. . .
When you’re finished, save and exit the file.
For the changes to take effect, restart AppArmor:
- sudo systemctl restart apparmor
Note: If you skipped the AppArmor configuration step, you will receive the following error message:
OutputJob for mysql.service failed because the control process
exited with error code. See "systemctl status mysql.service"
and "journalctl -xe" for details.
Since this message doesn’t make an explicit connection between AppArmor and the data directory, this error can take some time to figure out.
Once you’ve properly configured AppArmor, you can move on to the next step.
Now it’s time to start MySQL. If you do, however, you’ll run into another error. Instead of an AppArmor issue, this error is caused by mysql-systemd-start
, a script that supports managing MySQL through systemd
. You can inspect this script with the following command:
- nano /usr/share/mysql/mysql-systemd-start
This script checks for the existence of either a directory, -d
, or a symbolic link, -L
, that matches the default data directory path. If it doesn’t find either of these, the script will trigger an error and prevent MySQL from starting:
. . .
if [ ! -d /var/lib/mysql ] && [ ! -L /var/lib/mysql ]; then
echo "MySQL data dir not found at /var/lib/mysql. Please create one."
exit 1
fi
if [ ! -d /var/lib/mysql/mysql ] && [ ! -L /var/lib/mysql/mysql ]; then
echo "MySQL system database not found. Please run mysql_install_db tool."
exit 1
fi
. . .
After you’ve inspected this file, close it without making any changes.
Since you need either an appropriate directory or symbolic link to start the server, you must create the minimal directory structure to pass the script’s environment check:
- sudo mkdir /var/lib/mysql/mysql -p
Now you’re ready to start MySQL:
- sudo systemctl start mysql
Confirm MySQL is running by checking the status:
- sudo systemctl status mysql
Output● mysql.service - MySQL Community Server
Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset:>
Active: active (running) since Wed 2022-03-23 20:51:18 UTC; 4s ago
Process: 17145 ExecStartPre=/usr/share/mysql/mysql-systemd-start pre (code=>
Main PID: 17162 (mysqld)
Status: "Server is operational"
Tasks: 38 (limit: 1132)
Memory: 376.7M
CGroup: /system.slice/mysql.service
└─17162 /usr/sbin/mysqld
To ensure that the new data directory is indeed in use, start the MySQL monitor:
- mysql -u sammy -p
Now query for the value of the data directory again:
- SELECT @@datadir;
Output+----------------------------+
| @@datadir |
+----------------------------+
| /mnt/volume-nyc1-01/mysql/ |
+----------------------------+
1 row in set (0.01 sec)
After you’ve restarted MySQL and confirmed that it’s using the new location, take the opportunity to ensure that your database is fully functional. Once you’ve finished, exit the database as in the following and return to the command prompt:
- exit
OutputBye
Now that you’ve verified the integrity of any existing data, you can remove the backup data directory:
- sudo rm -Rf /var/lib/mysql.bak
Then restart MySQL one final time:
- sudo systemctl restart mysql
And finally, confirm it’s working as expected by checking the status:
- sudo systemctl status mysql
Output● mysql.service - MySQL Community Server
Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset:>
Active: active (running) since Wed 2022-03-23 20:53:03 UTC; 4s ago
Process: 17215 ExecStartPre=/usr/share/mysql/mysql-systemd-start pre (code=>
Main PID: 17234 (mysqld)
Status: "Server is operational"
Tasks: 38 (limit: 1132)
Memory: 368.9M
CGroup: /system.slice/mysql.service
└─17234 /usr/sbin/mysqld
If the Active
line states active(running)
this confirms that MySQL is working.
In this tutorial, you learned how to move MySQL’s data directory to a new location and update Ubuntu’s AppArmor access control lists to accommodate the adjustment. Although we were using a block storage device, the instructions here should be suitable for redefining the location of the data directory regardless of the underlying technology.
For more information on managing MySQL’s data directories, check out the following sections in the official MySQL documentation:
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Writing for my future self so I don’t forget what to do.
stop mysql
add
sudo reboot
If I do the following, MySQL will not start.
I reinstalled MySQL and skipped the above direction in Step 4 of this tutorial and MySQL is working perfectly with my datadir on a separate drive. Maybe it’s permissions or something to do with AppArmor - but it obviously doesn’t need to exist in the releases I’m using.
I’m using a fresh install of Ubuntu 24.04, and MySQL 8.0.36 - both the latest releases as of this posting.
I followed all the steps, but mysql does not start with the error:
job for mysql.service failed because the control process exited with error code. See … for Details.
I have created the original mysql path, but it doesn’t seem to help?
Struggled for days trying to make this work in ans aws ec2 ubuntu image home folder. put in a root subfolder and it worked.
In case if you are changing the datadir to somewhere under “/home”, you also need to do these steps https://stackoverflow.com/a/58912528 That is: Edit file /lib/systemd/system/mariadb.service
to
and do
I followed all the steps but mysql failed to start. That comment helped me in my case: dba.stackexchange.com/a/212331
I wonder why the first time i used this process the database moving went according to plan (from
/var/lib/mysql
to/media/carlos/2u256_data/mysql
) but then I installed a second hard drive (SSD) and the same process fails to start the MySQL database at the end of the process (moving from/media/carlos/2u256_data/mysql
to/media/carlos/localSSD/mysql
). I have followed also @iPwnPancakes instructions but I keep getting anexit-code
when trying to start the database. Any ideas?If you want AppArmor to play nice with the new volume, add two new rules to the
/usr/sbin/mysqld
block in the/etc/apparmor.d/usr.sbin.mysqld
file. It should look like:These rules are the exact read/write/lock permissions used for the previous data directory (
/var/lib/mysql/
) for MySQL.After you have edited
/etc/apparmor.d/usr.sbin.mysqld
, restart the AppArmor service with:And then restart the MySQL service with:
As @SmallLightCyanDolphin stated, following the tutorial caused the mysql startup to fail.
And as @iamumairayub pointed out, it’s due to an AppArmor issue. But their solution is somewhat of the nuclear option, making AppArmor completely ignore any MySQL rules.
this step is unnecessary and will cause the mysql startup to fail: sudo mkdir /var/lib/mysql/mysql -p
For me, Mysql did not restart after doing all steps
When I ran
sudo systemctl status mysql
I sawBad file descriptor
errorI spent lots of time but then I found out it was AppArmor issue, I had to unlink AppArmor from Mysql