When the root or /var partition on a Linux database server runs low on disk space, a common remediation is to relocate MySQL’s data directory (datadir, located at /var/lib/mysql by default) onto a larger mounted volume (such as /db/mysql).
This guide walks through stopping MySQL, copying the data directory while preserving ownership and permissions, updating the server configuration, handling SELinux contexts on CentOS/RHEL, and verifying the service.
Before You Begin:
- Schedule a maintenance window: MySQL must be completely stopped while copying the physical data directory to prevent corruption.
- Take a full logical or physical backup before moving files.
- Verify that the target mount point (
/db) is mounted via/etc/fstabso it is available beforemysqldstarts at boot.
Step 1: Verify the Current Data Directory and Stop MySQL
Check the active datadir path from MySQL before stopping the daemon:
mysql -u root -p -e "SELECT @@datadir;"
Stop the mysqld service cleanly and confirm it is no longer running:
# CentOS / RHEL 6 (SysVinit)
sudo service mysqld stop
sudo service mysqld status
# CentOS / RHEL 7+ (systemd)
sudo systemctl stop mysqld
sudo systemctl status mysqld
Step 2: Copy the Data Directory to the New Volume
Create the destination directory and copy /var/lib/mysql while preserving ownership (mysql:mysql), permissions, and timestamps. Using cp -rp or rsync -av ensures file attributes remain intact:
sudo mkdir -p /db
sudo cp -rp /var/lib/mysql /db/
Alternatively, with rsync:
sudo rsync -av /var/lib/mysql /db/
Verify that /db/mysql is owned by mysql:mysql:
ls -ld /db/mysql
Step 3: Update /etc/my.cnf
Edit /etc/my.cnf and update datadir and socket under [mysqld]. Also add a [client] section (or keep a symlink at /var/lib/mysql) so local CLI tools (mysql, mysqladmin, mysqldump) can locate mysql.sock:
sudo vim /etc/my.cnf
Example /etc/my.cnf:
[mysqld]
datadir=/db/mysql
socket=/db/mysql/mysql.sock
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
[client]
socket=/db/mysql/mysql.sock
Step 4: Update Init Script Defaults (CentOS/RHEL 6 SysVinit Only)
On CentOS/RHEL 6 systems using the legacy /etc/rc.d/init.d/mysqld script, check the fallback defaults passed to get_mysql_option if the init script overrides or checks /var/lib/mysql:
sudo vim /etc/rc.d/init.d/mysqld
Ensure datadir and socket defaults reflect /db/mysql:
get_mysql_option mysqld datadir "/db/mysql"
datadir="$result"
get_mysql_option mysqld socket "$datadir/mysql.sock"
socketfile="$result"
get_mysql_option mysqld_safe log-error "/var/log/mysqld.log"
errlogfile="$result"
get_mysql_option mysqld_safe pid-file "/var/run/mysqld/mysqld.pid"
mypidfile="$result"
(Note: On CentOS/RHEL 7+ with systemd, editing the init script is not required; mysqld reads /etc/my.cnf directly.)
Step 5: Configure SELinux Contexts (When SELinux is Enforcing)
On CentOS and RHEL systems where SELinux is in Enforcing mode (getenforce), mysqld will be denied access to /db/mysql unless the directory carries the mysqld_db_t SELinux file context.
Apply the permanent SELinux fcontext rule and restore labels on /db/mysql:
sudo semanage fcontext -a -t mysqld_db_t "/db/mysql(/.*)?"
sudo restorecon -Rv /db/mysql
Verify the context with ls -dZ /db/mysql.
Step 6: Back Up the Old Directory and Create a Compatibility Symlink
Rename the original /var/lib/mysql directory as a fallback until you have verified the migration, and optionally create a symbolic link for any local applications hardcoded to look for /var/lib/mysql/mysql.sock:
sudo mv /var/lib/mysql /var/lib/mysql_old
sudo ln -s /db/mysql /var/lib/mysql
sudo chown -h mysql:mysql /var/lib/mysql
Step 7: Start MySQL and Verify
Start the mysqld service and verify that it initializes cleanly from the new data directory:
# CentOS / RHEL 6
sudo service mysqld start
# CentOS / RHEL 7+
sudo systemctl start mysqld
Log in to MySQL and confirm @@datadir points to /db/mysql/ and all databases are accessible:
mysql -u root -p -e "SELECT @@datadir, @@socket; SHOW DATABASES;"
Once you have verified that all databases and applications are functioning normally, remove the old /var/lib/mysql_old backup copy to reclaim disk space on /var:
sudo rm -rf /var/lib/mysql_old
Troubleshooting
- Service fails to start with
Permission denied:- Check directory ownership:
chown -R mysql:mysql /db/mysql. - Ensure parent directory
/dbhas execute (x) traversal permissions (0755) for themysqluser. - Check
/var/log/audit/audit.logfor SELinux denials (avc: denied) and runrestorecon -Rv /db/mysql.
- Check directory ownership:
Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock': Addsocket=/db/mysql/mysql.sockunder the[client]section in/etc/my.cnfor keep the/var/lib/mysql -> /db/mysqlsymlink in place.