errcode: 13或permission denied八成是selinux上下文不匹配;先运行getenforce(输出enforcing)、sestatus(确认enforcing模式)和ausearch -m avc -ts recent | grep mysqld验证,再用setenforce 0临时测试,若mysql随即启动成功即可确认,最后用semanage fcontext与restorecon修复上下文。

80%以上的 MySQL 启动失败报 Errcode: 13 或 Permission denied,根源不是 chmod 没设对,而是 SELinux 上下文不匹配。
怎么快速确认是 SELinux 拦的而不是权限问题
看到 Can't create/write to file './ibdata1' (Errcode: 13) 或 Permission denied 却 ls -ld /var/lib/mysql 显示属主、权限都正确,就该怀疑 SELinux。别改权限,先运行:
-
getenforce—— 输出Enforcing就基本坐实了 -
sestatus—— 看Current mode是否为enforcing,Loaded policy name通常是targeted -
ausearch -m avc -ts recent | grep mysqld—— 有输出即实锤(若提示 command not found,先装audit) -
journalctl -u mysqld -n 50 --no-pager | grep -i "avc\|selinux"—— systemd 日志里常带关键词
临时验证:执行 sudo setenforce 0,再 systemctl start mysqld。如果立刻成功,问题闭环——就是上下文没标对。
为什么 chown mysql:mysql 还是报错
因为 SELinux 不看传统 DAC 权限(用户/组/读写执行),它检查的是每个文件/目录的 security context。即使 /var/lib/mysql 属主是 mysql:mysql,只要它的上下文类型不是 mysqld_db_t,mysqld 进程就会被拒绝写入。
查当前上下文:ls -Z /var/lib/mysql。正常应含 mysqld_db_t;若显示 default_t、var_lib_t 或 unconfined_u:object_r:default_t:s0,就是它。
典型 audit 日志片段:avc: denied { write } for ... tcontext=unconfined_u:object_r:default_t:s0 —— 关键在 tcontext 值。
怎样给 MySQL 数据目录打对 SELinux 标签
必须用 semanage fcontext 声明规则 + restorecon 生效,不能只靠 chcon 临时改(重启或重装后丢失):
- 标准路径:
sudo semanage fcontext -a -t mysqld_db_t "/var/lib/mysql(/.*)?"(注意(/.*)?表示递归子目录) - 自定义路径(如
/data/mysql):sudo semanage fcontext -a -t mysqld_db_t "/data/mysql(/.*)?" - socket 文件:
sudo semanage fcontext -a -t mysqld_var_run_t "/var/lib/mysql/mysql\.sock"(点号要转义) - 立即生效:
sudo restorecon -Rv /var/lib/mysql
若提示 command not found,RHEL/CentOS 8+ 装 policycoreutils-python-utils,7 装 policycoreutils-python。
Docker 挂载宿主机目录时 SELinux 失效怎么办
在启用 SELinux 的宿主机上,用 -v /my/data:/var/lib/mysql 启动容器,即使宿主机目录权限全开,也会因上下文继承失败被拒——容器内路径默认继承宿主机的 default_t,而非 mysqld_db_t。
错误日志里看不到 SELinux 字样,只报 Permission denied 或 can't create ./ibdata1。
两种解法:
-
推荐(宿主机预处理):
sudo semanage fcontext -a -t mysqld_db_t "/my/data(/.*)?"→sudo restorecon -Rv /my/data -
运行时自动修正:加
:z标签启动:docker run -v /my/data:/var/lib/mysql:z
漏掉一个路径(比如 /tmp/ib*、自定义 pid-file、插件目录 plugin_dir)就可能卡在某一步静默失败——ausearch -m avc -ts recent | grep mysqld 是唯一能暴露真实拦截点的方式。











