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/fstab so it is available before mysqld starts 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.


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:
    1. Check directory ownership: chown -R mysql:mysql /db/mysql.
    2. Ensure parent directory /db has execute (x) traversal permissions (0755) for the mysql user.
    3. Check /var/log/audit/audit.log for SELinux denials (avc: denied) and run restorecon -Rv /db/mysql.
  • Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock': Add socket=/db/mysql/mysql.sock under the [client] section in /etc/my.cnf or keep the /var/lib/mysql -> /db/mysql symlink in place.

References