≡ Menu

How to Move MySQL Data Directory to New Location on CentOS and Ubuntu

By default MySQL database will be created under /var/lib/mysql directory.

This might be Ok if you are running a small database that doesn’t take much space. But on production, for a larger database, you might not have enough space under root partition.

In that case, you may want to move your MySQL database from root partition to a different partition.

To change the MySQL directory, on a high level, you have to perform the following three steps:

  1. Move MySQL database files from /var/lib/mysql to a different partition
  2. Modify the my.cnf file with the new directory location
  3. Update security settings to reflect the directory change: On CentOS or RedHat, modify SELinux settings. On Ubuntu or Debian, modify the AppArmor settings.

This tutorial explains the details on how to perform the above three steps to move your MySQL data to a different directory.

Take a Backup of Current MySQL

Before you do anything, stop the MySQL database and take a cold backup of your database.

By default MySQL will database will be under /var/lib/mysql directory. Copy this mysql directory to a different location for backup.

service mysqld stop

cp -r /var/lib/mysql /backup/mysql

Or, if you prefer, you can use mysqldump to take a MySQL DB backup.

Move MySQL Data Directory to Different Partition

In this example, my root partition is /dev/sda1, which doesn’t have much space for the default /var/lib/mysql directory. But, I have /data partition on /dev/sdb1 disk which has lot of space.

So, I’ll be moving the MySQL database from / partition to /data partition.

Create the following directory and move the mysql data from /var/lib to /data/var/lib as shown below.

mkdir -p /data/var/lib

cd /var/lib

mv mysql /data/var/lib/

Few points to consider:

  • You can also move mysql directory to /data/var/lib/ directory, and create a symbolic link from /var/lib pointing to /data/var/lib. But, In this particular instance, I prefer the above simple moving the directory without symbolic link to avoid confusion.
  • If possible, try to use the move command to move the directory over (instead of copy). When you perform copy, the SELinux context will be lost, and you have to manually set those later (as explained below). But, when you move, the appropriate SELinux context for MySQL are kept in tact and you don’t have to worry about changing it.

Also, if you’ve copied the directory (instead of move), make sure you change the ownership appropriately. If not, you might get this error message: MySQL error: 1017Can’t find file: (errno: 13)

chown -R mysql:mysql /data

Modify my.cnf and Start MySQL

In the /etc/my.cnf file, you need to modify both datadir and socket parameter and point them to the new directory as shown below.

# vi /etc/my.cnf
datadir=/data/var/lib/mysql
socket=/data/var/lib/mysql/mysql.sock

Finally, restart the MySQL database.

# service mysqld start
Starting mysqld:  [  OK  ]

If you have a tmpdir parameter already defined in your my.cnf file, change the directory for that parameter also:

tmpdir=/data/var/lib/mysql

After changing the datadir and socket in the my.cnf file, if MySQL doesn’t start, or fails with a permission denied error message, then you need to set the SELinux (or AppArmor) as explained in the following sections.

SELinux Context Type for MySQL

Use ls -Z command to view the SELinux context. Before moving the directory, the following was the SELinux context on my MySQL database. In this example, “thegeekstuff” is the MySQL database under /var/lib/mysql directory.

As you see here, mysqld_db_t is the SELinux context type.

# ls -Z /var/lib/mysql
drwx------. mysql mysql unconfined_u:object_r:mysqld_db_t:s0 thegeekstuff
-rw-rw----. mysql mysql unconfined_u:object_r:mysqld_db_t:s0 ibdata1
-rw-rw----. mysql mysql unconfined_u:object_r:mysqld_db_t:s0 ib_logfile0
..

After moving the directory to the new location, you should see the exact SELinux as pre-move.

ls -Z /data/var/lib/mysql

Note: If you did a copy of the directory (instead of move), you’ll notice that it has changed. In that case, change the SELinux context as explained below.

When the SELinux context is wrong, you’ll see following error message (or something similar to this) in your audit log (or /var/log/messages)

# cat /var/log/audit/audit.log:
type=AVC msg=audit(1447281394.928:20831): avc:  denied  { read } for  pid=21346 comm="mysqld" name="mysql" dev=sda1 ino=5506027 scontext=unconfined_u:system_r:mysqld_t:s0 tcontext=unconfined_u:object_r:var_lib_t:s0 

Also, you’ll see the following in your mysqld.log file when MySQL DB failed to start.

# cat /var/log/mysqld.log:
mysqld_safe Starting mysqld daemon with databases from /var/lib/mysql
[Warning] Can't create test file /var/lib/mysql/devdb..lower-test
/usr/libexec/mysqld: Can't change dir to '/var/lib/mysql/' (Errcode: 13)
[ERROR] Aborting
[Note] /usr/libexec/mysqld: Shutdown complete

SELinux Setup for MySQL on CentOS / RedHat (Option 1)

Using chcon command, you can change the SELinux context type in the new directory as shown below.

chcon -R -t mysqld_db_t /data

In the above command:

  • chcon is the command to change the SELinux context
  • -R option will recursively change context for the given directory and all the sub directory.
  • -t option is used to specify the SELinux context type that should be set. In this example, we are setting it to mysqld_db_t type.
  • /data is the directory on which this command will be executed.

Note: Start changing the context from the top level directory /data (and not from the mysql directory), which will include mysql directory and all the sub-directory and files.

SELinux Setup for MySQL on CentOS / RedHat (Option 2)

Using restorecon command, you can restore the SELinux context to the correct type. But, in this case, you should inform SELinux what is the correct context by adding mysqld_db_t type to the SELinux context map.

To add the SELinux type to the context map, use the semanage command. Install policycoreutils-python package which contains semanage command.

yum -y install policycoreutils-python

Next, execute the following command to set the SELinux context map on the new directory.

semanage fcontext -a -t mysqld_db_t "/data(/.*)?"

In the above command, we are adding mysqld_db_t to the context map for the /data directory all the sub-directories and files underneath.

Finally, use the restorecon command, which will restore the appropriate SELinux context to the new /data directory.

restorecon -Rv /data 

Verify that the moved new /data directory and mysql sub-folders has the correct SELinux context.

# ls -Z /data/var/lib/mysql
drwx------. mysql mysql unconfined_u:object_r:mysqld_db_t:s0 thegeekstuff
-rw-rw----. mysql mysql unconfined_u:object_r:mysqld_db_t:s0 ibdata1
-rw-rw----. mysql mysql unconfined_u:object_r:mysqld_db_t:s0 ib_logfile0
..

Note: You can also use -e option along with the fcontext. This will make the context label for the /data and its subdirectories same as the context label of /var/lib/mysql

semanage fcontext -a -e /var/lib/mysql /data

AppArmor Setup for MySQL on Ubuntu / Debian

After moving the MySQL data diretory to a new location, if you don’t do the following, on Ubuntu, you will get this error while starting the mysql database: “(errno: 13)” (permission denied).

Modify the usr.sbin.mysqld file as shown below, and add the following two lines. Don’t forget the comma at the end of the line, which is required.

# vi /etc/apparmor.d/usr.sbin.mysqld
/data/var/lib/mysql/ r,
/data/var/lib/mysql/** rwk,

Next, execute the following command to reparse this new apparmor config file for mysql, and restart the apparmor.

sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.mysqld

sudo /etc/init.d/apparmor reload

Note: Alternatively, you can also add an alias in the AppArmor alias file as shown below. Again, don’t forget the comma at the end of this alias line.

# vi  /etc/apparmor.d/tunables/alias
alias /var/lib/mysql/ -> /newpath/,

MySQL Client socket Parameter

After the above change, you might be getting this error message while connecting from mysql client: ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/lib/mysql/mysql.sock’ (2)

# mysql -u root -pMyPassword
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)

If that happens, pass the –socket parameter to the mysql client, and point it to the mysql.sock file that is located under the new directory.

mysql -u root -pMyPassword --socket=/data/var/lib/mysql/mysql.sock

If you are calling mysql client locally, you can also use -h option and pass 127.0.0.1 as shown below. This will also avoid the mysql.sock error message.

mysql -u root -pMyPassword -h127.0.0.1
Add your comment

If you enjoyed this article, you might also like..

  1. 50 Linux Sysadmin Tutorials
  2. 50 Most Frequently Used Linux Commands (With Examples)
  3. Top 25 Best Linux Performance Monitoring and Debugging Tools
  4. Mommy, I found it! – 15 Practical Linux Find Command Examples
  5. Linux 101 Hacks 2nd Edition eBook Linux 101 Hacks Book

Bash 101 Hacks Book Sed and Awk 101 Hacks Book Nagios Core 3 Book Vim 101 Hacks Book

Comments on this entry are closed.

  • Step May 12, 2016, 3:23 am

    it is a good short manual!
    Thank you!

  • hemant jadhav June 2, 2016, 10:52 pm

    simple and short method. I faced all the problems which are discussed here.Now logic behind some steps are clear.

  • Collette June 6, 2016, 8:18 am

    Why not do the following:

    1. Stop mysqld
    2. Rename /var/lib/mysql to /var/lib/mysql-backup
    3. Create a volume on a raid array or hard drive with enough space
    4. Mount that volume under /var/lib/mysql
    5. Copy all files from /var/lib/mysql-backup to /var/lib/mysql
    6. Start myslqd

    That way the mysql databases are still at the original location.

  • Tomas June 10, 2016, 9:25 am

    Changes made with the chcon command do not survive a file system relabel, or the execution of the restorecon command. Forget the chcon command and always use semanage.

  • Heather July 19, 2016, 6:21 pm

    Thanks for this quick & easy!

    Re: “ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/lib/mysql/mysql.sock’ (2)” – to prevent this error, you can add the socket location to your my.cnf file, eg:

    [client]
    socket=/newpath/to/mysql/mysql.sock

  • Sven the Barbarian December 27, 2016, 7:22 pm

    An extra note that had me stumped for a day (running Ubuntu), would give me the same error as you would expect with AppArmour not configured, ie:

    Starting mysql (via systemctl): mysql.serviceJob for mysql.service failed because the control process exited with error code. See “systemctl status mysql.service” and “journalctl -xe” for details

    Is that MySql required the default data directory to exist, even though it was not being pointed to. Fixed by creating the dir:

    sudo mkdir /var/lib/mysql/mysql -p

    Picked this up from here, I ignored it for a day because nowhere else mentioned it and it seemed so silly.

  • Anirudh yadav December 28, 2016, 5:35 pm

    For some reason I am seeing this error whenever I to startup mysql after changing the data directory (followed instructions here: http://www.thegeekstuff.com/2016/05/move-mysql-directory/comment-page-1/) to something different.

    2016-12-28T23:12:48.369028Z 0 [Note] InnoDB: Loading buffer pool(s) from /data/mysql/var/lib/mysql//ib_buffer_pool
    2016-12-28T23:12:48.369217Z 0 [ERROR] InnoDB: Cannot open ‘/data/mysql/var/lib/mysql//ib_buffer_pool’ for reading: Permission denied
    2016-12-28T23:12:48.369344Z 0 [Note] Plugin ‘FEDERATED’ is disabled.
    2016-12-28T23:12:48.377825Z 0 [Note] Server hostname (bind-address): ‘*’; port: 3306
    2016-12-28T23:12:48.378334Z 0 [Note] IPv6 is available.
    2016-12-28T23:12:48.378352Z 0 [Note] – ‘::’ resolves to ‘::’;
    2016-12-28T23:12:48.378370Z 0 [Note] Server socket created on IP: ‘::’.
    2016-12-28T23:12:48.378770Z 0 [ERROR] Could not create unix socket lock file /data/mysql/var/lib/mysql/mysql.sock.lock.
    2016-12-28T23:12:48.378779Z 0 [ERROR] Unable to setup unix socket lock file.
    2016-12-28T23:12:48.378783Z 0 [ERROR] Aborting
    I checked my audit report to see if it reported something for those permissions issues and I see nothing:

    [root@RCOVLNX3081 ~]# cat /var/log/audit/audit.log | grep ib_buffer_po
    [root@RCOVLNX3081 ~]# cat /var/log/audit/audit.log | grep mysql.sock.lock
    [root@RCOVLNX3081 ~]#
    I also checked the security context for the files and made sure that the mysql_db_t had access to the file

    [root@RCOVLNX3081 ~]# ls -RZ /data/mysql/var/lib/ | grep ib_buffer_pool
    -rw-r—–. mysql mysql unconfined_u:object_r:mysqld_db_t:s0 ib_buffer_pool
    to force any permissions issues with the permissions i changed:

    [root@RCOVLNX3081 ~]# chcon -Rt mysqld_db_t /data/mysql/var/lib/mysql
    [root@RCOVLNX3081 ~]# ls -RZ /data/mysql/var/lib/ | grep -v mysqld_db_t
    /data/mysql/var/lib/:

    /data/mysql/var/lib/mysql:

    /data/mysql/var/lib/mysql/mysql:

    /data/mysql/var/lib/mysql/performance_schema:

    /data/mysql/var/lib/mysql/sys:
    Still the same error. Please help.

    here is the content of my.cnf file:

    # For advice on how to change settings please see
    # http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html

    [mysqld]
    #
    # Remove leading # and set to the amount of RAM for the most important data
    # cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
    # innodb_buffer_pool_size = 128M
    #
    # Remove leading # to turn on a very important data integrity option: logging
    # changes to the binary log between backups.
    # log_bin
    #
    # Remove leading # to set options mainly useful for reporting servers.
    # The server defaults are faster for transactions and fast SELECTs.
    # Adjust sizes as needed, experiment to find the optimal values.
    # join_buffer_size = 128M
    # sort_buffer_size = 2M
    # read_rnd_buffer_size = 2M
    #datadir=/var/lib/mysql
    #socket=/var/lib/mysql/mysql.sock

    datadir=/data/mysql/var/lib/mysql
    socket=/data/mysql/var/lib/mysql/mysql.sock

    # Disabling symbolic-links is recommended to prevent assorted security risks
    symbolic-links=0

    log-error=/var/log/mysqld.log
    pid-file=/var/run/mysqld/mysqld.pid

  • Ananth Ch J April 2, 2017, 11:56 am

    Hello Anirudh, hope you might have already fixed your issue. From your error log it seems that innodb engine has failed due to innodb_buffer pool. I would suggest you to set your innodb_buffer_pool_size value more than 70% of your systems RAM Size.