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:
- Move MySQL database files from /var/lib/mysql to a different partition
- Modify the my.cnf file with the new directory location
- 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
Comments on this entry are closed.
it is a good short manual!
Thank you!
simple and short method. I faced all the problems which are discussed here.Now logic behind some steps are clear.
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.
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.
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
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.
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
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.