Linux下MariaDB安装与数据目录迁移实战指南
2026/9/17 17:21:34 网站建设 项目流程

我去年接了一个内部小项目的维护,业务数据三个月涨了快 40G,系统盘眼看着就飘红了。当时最直接的办法就是把 MariaDB 的数据目录从 /var/lib/mysql 迁到挂载在 /data 下的独立数据盘,顺便把安装配置也重新梳理了一遍。这类“Linux 安装 MariaDB + 修改存储路径”的需求在运维日常里太典型了,不管是自学 Linux 数据库部署、给公司服务器做数据盘扩容,还是准备面试实操,都能用得上。这篇文章我就把完整流程拆开讲清楚:从环境准备、源的选择、安装初始化,再到数据目录迁移、权限处理和安全策略调整,每一步都给出能直接复现的操作,也会把背后的原理和踩过的坑一并交代。

1. 迁移存储路径之前,先搞清楚场景和风险

1.1 什么情况下需要改存储路径

很多朋友第一次接触“修改 MariaDB 存储路径”这个需求,第一反应是:默认装在 /var/lib/mysql 不就行了?确实,小项目、测试环境随便跑都没问题。但真实生产环境里,改存储路径几乎是业务增长后绕不开的一步。

最常见的情况就是系统盘空间不够。云服务器默认系统盘一般就 40G 到 80G,MariaDB 的数据文件、binlog 日志、redo log 全堆在根分区,业务一旦跑起来,膨胀速度远超预期。其次是数据盘隔离需求:很多业务要求数据库必须落在独立的数据盘或者专门的 SSD 上,不能跟系统盘抢 IO。再有就是迁移场景,比如要把数据库从旧机器搬到新机器,或者从机械盘换到 NVMe 盘,这时候也需要重新规划数据目录。

不过有一点要提醒:改存储路径不是简单的 mv 一下就行,它牵扯到 datadir 参数、socket 路径、pid 文件、日志位置、SELinux/AppArmor 安全策略,还有整个数据文件的一致性。如果只改一半,最常见的结果就是服务起不来,或者起来后客户端连不上。

1.2 MariaDB 在 Linux 上的默认目录布局

动手之前,先把 MariaDB 在 Linux 上的默认布局搞清楚,后面迁移的时候才知道哪些东西要跟着动,哪些可以保持不变。不同发行版会略有差异,但整体上差不多:

目录/文件默认位置说明
数据目录/var/lib/mysql所有库表文件、ibdata1、undo 日志、redo log
主配置文件/etc/my.cnf或 /etc/my.cnf.d/ 下的多个配置片段
错误日志/var/log/mariadb/mariadb.log启动和运行时的错误记录
socket 文件(Debian系)/run/mysqld/mysqld.sock本地客户端连接用
socket 文件(RHEL系)/var/lib/mysql/mysql.sock有些版本默认在这里
pid 文件/var/run/mariadb/mariadb.pid记录服务进程号

数据目录里存放的内容很多人会有误解,以为只有库名对应的文件夹。实际上 /var/lib/mysql 下面除了 mysql、performance_schema、sys 这些系统库目录,还有 ibdata1、ib_logfile0/1 这类 InnoDB 核心文件,以及临时的 ibtmp1。修改存储路径时,整个目录都要搬走,不能只挪某个库。

1.3 迁移前必须完成的三件事

我见过太多人上来就改配置,结果数据搬了一半发现回不去。这里先列三个必做项,顺序不能乱:

第一,确认全量备份存在。不管用什么方式,mysqldump 导出来的 SQL 也好,物理目录打包也好,必须有一份能用的备份。迁移过程中如果数据文件损坏,至少能还原。我的习惯是迁移前做一次逻辑备份放系统盘以外的地方,双保险。

第二,确认服务可以正常停止。迁移期间数据库要处于完全关闭状态,不能有连接还在写。建议选业务低峰期操作,提前跟业务方打好招呼,避免出现停止服务后还有应用在重连的尴尬。

第三,确认目标磁盘已经挂载好,而且在 /etc/fstab 中有持久化配置。否则服务器重启后新目录变成空目录,数据库会因为找不到 datadir 而启动失败。这也是新手最容易忽略的:df -h 看盘明明是满的,实际是没挂载。

2. Linux 环境准备与 MariaDB 安装

2.1 环境确认与安装源选型

安装第一步不是敲 yum install 或者 apt install,而是确认系统环境和架构。先跑一下:

cat /etc/os-release uname -m

常见的发行版分两大系:RHEL 系(CentOS、Rocky Linux、AlmaLinux、Oracle Linux)和 Debian 系(Ubuntu、Debian)。两个系的包管理器和初始化方式不同,安装源也不同。

安装源这块,我强烈建议用官方软件仓库,而不是直接用发行版自带的源。原因很简单:系统自带源里的 MariaDB 版本往往偏旧,比如 Ubuntu 22.04 自带的还是 10.6 系列,而官方源能直接装到 10.11 LTS 甚至 11.x 的稳定版,性能和 bug 修复都更好。另外官方源对 ARM 架构也很友好,这在国产化服务器场景里很实用。

2.2 RHEL 系安装步骤

以 Rocky Linux 9 为例,先配置官方 MariaDB 源。可以访问官网的仓库生成工具,也可以手动写一个源文件。手动配置的方式是新建 /etc/yum.repos.d/mariadb.repo:

[mariadb] name = MariaDB baseurl = https://mirror.mariadb.org/yum/11.4/rhel/9/x86_64/ gpgkey = https://mirror.mariadb.org/yum/RPM-GPG-KEY-MariaDB gpgcheck = 1

注意 baseurl 里的版本号,11.4 是目前企业级用得比较多的稳定分支。装完源之后:

sudo dnf install -y mariadb-server mariadb-client sudo systemctl enable --now mariadb

这里要解释一个细节:为什么用 dnf 而不用 yum。在 Rocky 9、AlmaLinux 9 这类新版本里,yum 只是个兼容别名,底层还是 dnf,直接敲 dnf 体验更好,报错信息也更清晰。

2.3 Debian 系安装步骤

Debian 系稍微麻烦一点,因为官方源需要手动导入签名密钥。以 Ubuntu 22.04 为例:

sudo apt update sudo apt install -y wget sudo apt install -y mariadb-server mariadb-client

如果你想装官方源里的新版本,可以这样操作:

sudo apt install -y software-properties-common sudo mkdir -p /etc/apt/keyrings sudo wget -qO /etc/apt/keyrings/mariadb-keyring.pgp https://mirror.mariadb.org/yum/RPM-GPG-KEY-MariaDB

然后在 /etc/apt/sources.list.d/ 下添加源文件,写入:

deb [signed-by=/etc/apt/keyrings/mariadb-keyring.pgp] https://mirror.mariadb.org/repo/11.4/ubuntu jammy main

更新源后安装:

sudo apt update sudo apt install -y mariadb-server mariadb-client

2.4 安装后的初始化与连接验证

安装完成后,第一件要做的事就是初始化安全配置。执行:

sudo mariadb-secure-installation

这个命令会引导你设置 root 密码、删除匿名用户、禁止 root 远程登录、删除 test 库。中间的选项全部按推荐值选就行,生产环境建议全选 yes。

然后验证服务状态和默认数据目录:

systemctl status mariadb mysql -u root -p -e "SHOW VARIABLES LIKE 'datadir';"

正常情况下你会看到后面小节里要改的 datadir 还是默认的 /var/lib/mysql。这时候整个数据库已经能跑了,可以建个测试库,插几条数据,为了后面迁移验证做准备:

mysql -u root -p -e "CREATE DATABASE test_migrate; USE test_migrate; CREATE TABLE t1 (id INT PRIMARY KEY, name VARCHAR(50)); INSERT INTO t1 VALUES (1, 'hello');"

3. 修改 MariaDB 存储路径的完整实操

3.1 目录规划与磁盘挂载检查

这一步是迁移的核心。首先确定你要把数据放到哪个目录,我建议用 /data/mysql,而不是直接使用 /data。原因很简单:/data 是数据盘的挂载点,里面可能还有其他业务目录,提前建一个独立子目录,权限隔离和后续运维都更清晰。

先看一下磁盘挂载情况:

lsblk df -h cat /etc/fstab

如果目标数据盘还没格式化挂载,可以用下面的流程:

sudo mkfs.xfs /dev/sdb # 新盘,注意确认盘符,别把自己的系统盘格式化了 sudo mkdir -p /data echo '/dev/sdb /data xfs defaults 0 0' | sudo tee -a /etc/fstab sudo mount -a df -h

这里有个容易被忽略的坑:如果数据盘之前已经挂过,但 fstab 没写,重启后会掉盘。掉盘之后 MariaDB 启动时会发现 datadir 指向的 /data/mysql 不存在,直接报错起不来。所以每次改完 fstab 后,建议用 mount -a 先验证一遍,再重启验证一遍。

3.2 数据目录迁移的详细步骤

现在进入核心环节。整个过程按以下步骤操作,每一步都有它的理由,不要跳步。

第一步,备份。既然已经跑了一个测试库,先导出一份逻辑备份:

mysqldump -u root -p --all-databases --single-transaction --routines --events --triggers > /tmp/mariadb_backup_$(date +%Y%m%d).sql

加 --single-transaction 是为了保证备份数据的一致性,不会因为并发写入导致逻辑不一致。加了 --routines、--events、--triggers 是为了把存储过程、定时事件、触发器都包含进去。很多人只导出表数据,导入后才发现存储过程没了,就是这个原因。

第二步,停止服务:

sudo systemctl stop mariadb

停止后确认没有残留进程:

ps aux | grep mariadbd | grep -v grep

这一步很关键。systemctl stop 之后如果还有残留的 mariadbd 进程,数据文件可能还在被写入,这时候复制目录拿到的文件就是不一致的。

第三步,创建目标目录并调整属主:

sudo mkdir -p /data/mysql sudo chown mysql:mysql /data/mysql sudo chmod 751 /data/mysql

属主一定要是 mysql:mysql,否则启动时进程没有权限写数据目录。权限设 751 是为了让 mysql 用户能读写目录,其他用户只能进入,这个权限组合在生产环境比较常见。

第四步,复制数据文件。这里我推荐用 rsync,而不是 mv。为什么?因为 rsync 能在保留权限、属主、软链接的同时进行增量复制,万一中途失败可以重跑,而 mv 是把整个目录直接搬走,原目录就没有了,回滚会变得很麻烦。命令如下:

sudo rsync -avp /var/lib/mysql/ /data/mysql/

-a 是归档模式,保留权限、属主、时间戳等属性;-v 是显示进度;-p 是保留文件权限。复制完成后,可以对比一下两个目录的内容:

sudo diff -r /var/lib/mysql /data/mysql

没有输出说明两边文件一致。复制完成后,原目录先别急着删,把它改名留作回滚:

sudo mv /var/lib/mysql /var/lib/mysql.bak

3.3 修改配置文件:datadir、socket 与日志联动

数据文件搬完,接下来就是改配置。MariaDB 的配置加载顺序比较特殊,/etc/my.cnf 里会有 include 指令,把 /etc/my.cnf.d/ 目录下的文件全部加载进来。我的习惯是在 /etc/my.cnf.d/ 下新建一个专门的文件,比如 mariadb-datadir.cnf,这样改动集中、方便排查。

[mysqld] datadir=/data/mysql socket=/var/lib/mysql/mysql.sock pid-file=/var/run/mariadb/mariadb.pid log-error=/var/log/mariadb/mariadb.log

这里解释几个关键点:

datadir 不用说,这是数据目录的核心参数。socket 这里我特意保留成原来的 /var/lib/mysql/mysql.sock,但如果原目录不存在了,有些客户端连接会出问题。稳妥的做法是创建一个软链接,或者直接用默认的系统 socket 路径,比如 Debian 系用 /run/mysqld/mysqld.sock,RHEL 系用 /var/lib/mysql/mysql.sock。如果你把 socket 改了,客户端连接时也要指定新的 socket:

mysql -u root -p -S /tmp/mysql.sock

其实更简单的通用做法是把 socket 放到 /tmp 下,几乎所有 PHP、Python 配置都能识别,但要注意安全管理,/tmp 权限本身要锁好。这个看各人偏好。

pid-file 和 log-error 通常不需要改,因为这两个文件是运行时动态创建的,不存在“数据文件”的概念。但如果你遇到权限问题,可以把 pid-file 保持默认,log-error 保持默认,这个不影响存储路径的修改。

改完配置之后,还有一件事不能漏:如果原目录被改名成了 /var/lib/mysql.bak,而 socket 还是指向 /var/lib/mysql/mysql.sock,那就必须保证这个目录存在。我建议:

sudo mkdir -p /var/lib/mysql sudo ln -s /data/mysql/mysql.sock /var/lib/mysql/mysql.sock

这样原来走 socket 连接的程序不用改配置,还是按旧路径去找 socket 文件,实际上会被 LN 指向新目录下的 socket。

3.4 SELinux 与 AppArmor 安全策略调整

这一步是绝大多数教程不会重点讲,但实际最容易翻车的环节。很多人在修改目录后启动失败,日志里一堆 Permission denied,查了半天发现是 SELinux 或 AppArmor 拦着。

RHEL 系默认 SELinux 是 enforcing 模式。新数据目录 /data/mysql 没有被标上 mysqld_db_t 类型,MariaDB 进程就无法访问。解决办法有两个:

一是直接把 SELinux 关掉,这是我最不推荐的做法,等于把服务器的安全防线拆了。二是给新目录打上正确的 SELinux 上下文:

sudo dnf install -y policycoreutils-python-utils sudo semanage fcontext -a -t mysqld_db_t "/data/mysql(/.*)?" sudo restorecon -Rv /data/mysql

semanage 命令的作用是告诉 SELinux:/data/mysql 这个目录未来要作为 MariaDB 数据目录使用,预先登记它的文件类型。restorecon 则是把当前目录里已有的文件全部刷新成这个类型。做完之后可以用 ls -Z /data/mysql 确认:

ls -Z /data/mysql

Debian/Ubuntu 系是 AppArmor,情况类似。配置文件通常在 /etc/apparmor.d/usr.sbin.mariadbd,默认只允许访问 /var/lib/mysql 下的文件。修改后要在文件末尾加入:

/data/mysql/ rwk,

保存后重载 AppArmor:

sudo systemctl reload apparmor

不放心可以查看当前状态:

sudo aa-status | grep mariadbd

这一步不发愁的话,启动后大概率会报:

Failed to open log (file './ib_logfile0', errno 13)

这就是权限被拦截的典型表现。

3.5 启动验证与数据完整性检查

配置和权限都处理完之后,可以启动服务了:

sudo systemctl start mariadb systemctl status mariadb

如果启动失败,第一时间看错误日志:

sudo tail -50 /var/log/mariadb/mariadb.log

启动成功之后,逐个验证:

mysql -u root -p -e "SELECT @@datadir;" mysql -u root -p -e "SHOW DATABASES;" mysql -u root -p -e "USE test_migrate; SELECT * FROM t1;"

这里有一个小的经验:迁移完成后,不要急着删 /var/lib/mysql.bak。我通常的做法是让它保留 24 小时,经过一个完整的业务周期、确认新目录读写都正常之后,再清掉这份备份。虽然占点磁盘空间,但能让迁移风险降到最低。

4. 常见问题与排查技巧实录

4.1 启动失败案例速查表

迁移过程中最容易遇到的几个问题,我整理成一张表,方便直接对照排查。

报错现象可能原因排查思路常用解决命令
Can't create/write to file '/data/mysql/xxx'目录属主或权限不对检查目录属主和权限chown -R mysql:mysql /data/mysql
Failed to open log (file './ib_logfile0', errno 13)SELinux 或 AppArmor 拦截查看 SELinux/AppArmor 配置semanage fcontext / restorecon
Can't connect to local MySQL server through socketsocket 路径不匹配检查 client 配置和 socket 文件是否真实存在mysql -S /tmp/mysql.sock
Directory 'xxx' is not owned by mysql属主不正确检查目录 ownerchown -R mysql:mysql
[ERROR] InnoDB: Operating system error number 13权限或安全策略查看文件权限、上下文ls -Z 确认 SELinux 类型
[ERROR] MariaDB: File '/var/lib/mysql/mysql.sock' not found原目录被改名但 socket 还在旧路径创建符号链接或修改配置ln -s

我这里再强调一个实际场景:如果你恰好用的是一台开启了 SELinux 的国产化服务器(比如麒麟、统信 UOS 这些基于 RHEL 体系的系统),semanage 命令有可能不在 PATH 里,需要先安装 policycoreutils-python-utils。有些精简版系统连 policycoreutils 都没装,就得先dnf install policycoreutils-python-utils

4.2 客户端无法通过 socket 连接时的处理

迁移后很容易出现一个奇怪的现象:服务进程明明起来了,systemctl status mariadb也显示 active,但本地mysql -u root -p就是报“Can't connect to local MySQL server through socket”。

这个问题的根因在于配置优先级。MariaDB 读取 [client] 和 [mysqld] 两段配置,socket 参数在这两段中都要存在。如果你只改了 [mysqld] 里的 socket,但 [client] 段还指向旧路径,客户端就会用旧路径去找 socket 文件。最简单的排查方式:

mysql -u root -p -S /实际socket路径

能连上,就说明问题出在客户端连接的 socket 路径配置。这时候在 my.cnf.d 的配置文件里补一段:

[client] socket=/var/lib/mysql/mysql.sock

或者统一把所有 socket 都指向一个新路径,关键是 [mysqld] 和 [client] 必须一致。

另外还有一个容易被忽略的点:mysql.sock 文件是服务启动时创建的,如果你把原 /var/lib/mysql 目录整个改名了,而 socket 路径还指向里面,服务会在启动时尝试创建 socket 文件,但因为目录不存在,就会一直报错。所以我在前面建议做软链接,本质原因就在这里。

4.3 迁移后发现数据不完整的排查

这种情况最吓人,但通常不是数据真的丢了,而是迁移操作方式不对导致漏掉了文件。有一次我帮朋友排查,迁移后一个库少了三张表,看了半天才发现,他操作命令是cp /var/lib/mysql/* /data/mysql/,但当时服务没停,还有应用在写入,部分新写入的文件没复制到新目录。

这种问题的防范办法有两点:复制前必须确认服务完全停止,这是硬指标;复制后用 diff 或 rsync 校验两边目录是否完全一致。如果不放心,可以直接用 rsync 再跑一次校验模式:

sudo rsync -avp --checksum /var/lib/mysql/ /data/mysql/

不输出差异内容,说明两边一致。如果发现有遗漏,就用这条命令自动补上,然后重启服务。

另外要提醒表空间类型的问题:如果某些表使用了 InnoDB 独立表空间(file-per-table,默认开启),每个表对应一个 .ibd 文件;如果早期表是共享表空间,数据全在 ibdata1 里。复制目录时,这些文件都会被正常复制,不会出现逻辑遗漏。但如果你的表既有 InnoDB 又有 MyISAM,MyISAM 的三件套(.frm、.MYD、.MYI)也必须完整,任何一个缺失都会在查询时报错。

4.4 保留回滚方案,避免迁移翻车

无论准备得多充分,总有意外可能发生。所以我每次迁移都有一个固定动作:保留原目录,标记为不可被自动清理的文件。

如果迁移后出现完全不可恢复的问题,比如误删了某个重要目录、误改了配置导致反复启动失败,回滚流程只有四步:

sudo systemctl stop mariadb sudo mv /data/mysql /data/mysql.failed sudo mv /var/lib/mysql.bak /var/lib/mysql sudo systemctl start mariadb

改回配置里的 datadir 为 /var/lib/mysql,再启动服务。这样整个环境就恢复到迁移前状态。

这套回滚方案我建议你在真正迁移之前,先用测试库完整演练一遍。演练几次之后,你会对整个过程每个环节可能出的问题更有感觉,真正上生产的时候心里就有底。

5. 迁移后的日常维护与经验补充

5.1 磁盘空间监控与备份策略

迁移最大的收益就是给数据盘扩容腾出了空间,但空间是省出来了,监控不能停。我一般会在服务器上部署简单的磁盘告警脚本,或者直接用系统自带的 crontab 加一条:

0 * * * * df -h | awk 'NR==1 || /\/data/ {print}' >> /var/log/disk_usage.log

每天看一眼 /data 的占用趋势,心里就有数。备份策略上,我建议至少保留两套:一套是 mysqldump 的逻辑备份,适合数据量不大、需要整库恢复的场景;另一套是物理备份工具,MariaDB 自带的 mariadb-backup 可以做在线物理备份,适合数据量大、恢复时间要求高的场景。

很多人在迁移完成后就不管备份了,这是要不得的。迁移节点本身是数据结构最容易出问题的时机,如果新目录里数据文件存在 bug,几天后才发现,再想恢复就难了。

5.2 几个提升效率的 MariaDB 运维命令

这里分享几个我平时经常用的巡检命令,适合在迁移完成后的几天里反复检查:

# 查看数据目录实际占用 sudo du -sh /data/mysql # 查看当前连接数(连接数异常时最先要看这个) mysql -u root -p -e "SHOW PROCESSLIST;" # 查看 InnoDB 状态,关注 buffer pool 命中率等关键信息 mysql -u root -p -e "SHOW ENGINE INNODB STATUS\G" # 巡检所有库表完整性 mysqlcheck -u root -p --all-databases

这里说明一下,mysqlcheck 对 MyISAM 表可以做 check 和 repair,对 InnoDB 表主要是检查逻辑一致性。迁移完成后的第一次巡检,建议把所有库都 check 一遍,有问题尽早暴露。

还有一个实用的监控指标:datadir 所在分区的剩余空间。MariaDB 运行时,redo log、undo log、临时文件都会写在这个分区,如果空间满了,数据库会直接进入只读模式甚至崩溃。日常巡检时,df -h 里 /data 的使用率要保持在 80% 以下,这个目标要提前规划。

5.3 关于迁移路径的几点个人体会

最后说几个我自己折腾了几次才总结出来的体会。

第一次做数据目录迁移的时候,我犯过一个说大不大、说小不小的错:只改了 datadir,没管 socket,结果启动倒是成功了,但所有原本走 socket 连接的应用全部连不上。当时还怀疑是端口问题,查了半天才发现路径不匹配。所以后来我总结出一个原则:凡是涉及目录位置的改动,一定要把 client 端和 server 端的路径全部过一遍,不能只盯着 mysqld。

还有一个体会是关于参数调整的。迁移之后,很多人会顺手调 innodb_buffer_pool_size,因为换了新盘想提升性能。这个思路没错,但要注意顺序:先把迁移做稳定,再调参数。两个风险叠加在一起,出了问题你根本不知道是路径配置引出来的,还是参数设得不对引出来的。我的做法是迁移后保持原参数跑一天,确认一切正常后再根据监控数据逐步调整。

另外,如果你是在虚拟化环境里做这个操作,记得迁移前给整机做一个快照。快照回滚比任何备份都快,是最后一根救命稻草。虽然云平台的快照会占空间、收费,但比起数据库数据的安全性,这点成本非常值得。

这套流程走完,你得到的不仅是一个改过路径的 MariaDB,还有一套对目录结构、权限、安全策略的完整认知。以后再遇到类似的迁移需求,比如把 MySQL 数据目录迁走、把 binlog 单独放一个盘,思路都是通用的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询