先用docker logs 抓原始错误,重点看“Permission denied”前后的具体路径(如/var/lib/mysql/is_writable),再确认MySQL容器内用户UID/GID(默认999)、宿主机目录递归属主权限(chown -R 999:999)、SELinux/AppArmor拦截及父目录可穿越性。

看日志里具体哪条路径被拒绝
别急着改权限,先用 docker logs 抓原始错误。真正有用的不是“Permission denied”四个字,而是它前面或后面的路径——比如 /var/lib/mysql/is_writable、/tmp/ib7GBpJH、/var/log/mysql/error.log 或 /var/run/mysqld/mysqld.sock.lock。这些路径直接告诉你 MySQL 进程卡在哪一层。如果日志里只显示 chown: changing ownership of '/var/lib/mysql/': Permission denied,说明问题出在数据目录初始化阶段;如果报的是 Can't create test file,大概率是父目录或 datadir 本身属主没递归设对。
确认容器内 mysql 用户的 UID/GID 是多少
MySQL 8.0 官方镜像默认用 UID=999、GID=999 的 mysql 用户跑 mysqld,但这个值不是写死的,得实锤:
- 运行
docker run -ti --rm --entrypoint="/bin/bash" mysql:8.0.33 -c "id -u mysql && id -g mysql",输出两行999才算确认 - 别信文档或猜测,不同构建版本可能微调(比如某些定制镜像用 1001)
- 如果挂载了多个目录(如
/var/lib/mysql和/var/log/mysql),每个都得单独检查属主,不能只改 data 目录
宿主机目录属主和权限必须匹配且递归生效
常见错误是只改了顶层目录,漏掉子目录或文件:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 用
sudo chown -R 999:999 /home/zhangsan/mysql/data,-R不可省——ibdata1、mysql/子目录、auto.cnf都得是 999 - 权限建议
sudo chmod -R 750 /home/zhangsan/mysql/data:目录要 x(穿越权),组要 r-x(容器内组用户需能读取),其他用户不给任何权限 - 避免
chmod 777或chown zhangsan:mysql:前者不安全,后者在容器里无效(容器不解析宿主机用户名) - 如果挂载了
/tmp,也要同步处理:mkdir -p /home/zhangsan/mysql/tmp && sudo chown -R 999:999 /home/zhangsan/mysql/tmp && sudo chmod -R 1777 /home/zhangsan/mysql/tmp(tmp 需 sticky bit)
SELinux 或 AppArmor 拦截时现象很隐蔽
属主、权限全对,但容器还是起不来,且 docker logs 里没有明显路径级报错——这时候要怀疑安全模块:
- 查系统日志:
journalctl -u docker --since "1 hour ago" | grep -i avc(SELinux)或sudo aa-status(AppArmor) - 临时验证:CentOS/RHEL 上执行
sudo setenforce 0,Ubuntu 上执行sudo systemctl stop apparmor,再启动容器;若成功,就是它在拦 - 永久修复优先用上下文打标:
sudo semanage fcontext -a -t mysqld_db_t "/home/zhangsan/mysql/data(/.*)?",再sudo restorecon -Rv /home/zhangsan/mysql/data - 运行时加
:z标签(如-v /home/zhangsan/mysql/data:/var/lib/mysql:z)能自动重标,但仅限单容器独占该目录;多容器共享时要用:Z,注意它会禁用其他进程访问
最易被忽略的是:父目录的 x 权限(比如 /home/zhangsan/mysql 目录本身权限是 700 且属主不是 999,那即使 data 目录全对,容器也进不去)。用 namei -l /home/zhangsan/mysql/data 逐层检查可穿越性,比反复重启容器快得多。










