MySQL 建表报 1030,能查不能建,排查 1 小时发现是我自己改了一行权限

以为是存储引擎的锅,结果是两天前我亲手敲的 chown。

先说结论

如果你在 Docker 部署的 MySQL 里遇到:

  • 查询正常,建表报错 1030 (168)
  • 磁盘空间充足,SQL 语法没问题,没有残留文件

第一反应别查 MySQL,先查目录权限。

大概率是你在宿主机上 chown 了挂载目录,导致宿主机 UID 和容器内 UID 不匹配,容器里的 MySQL 用户"能读不能写"。


问题现场

环境:Ubuntu + Docker 部署 MySQL,数据挂载在宿主机 /opt/resumeai/docker/resumeai/mysql/data。

执行建表 SQL,报错:

css 复制代码
[HY000][1030] Got error 168 - 'Unknown (generic) error from engine' from storage engine

诡异的是:SELECT 正常,已有表的数据都能查,就是不能建新表。


排查过程

第一步:磁盘满了?

bash 复制代码
df -h   # 使用率 30%,空间充足
df -i   # inode 使用率 9%,也没问题

排除。

第二步:SQL 语法有问题?

同样的 SQL 在本地环境跑得通,表名也无特殊字符。

排除。

第三步:有残留的物理文件冲突?

bash 复制代码
ls /opt/resumeai/docker/resumeai/mysql/data/<库名>/ | grep release_note
# 无输出

没有残留的 .ibd 文件,排除。

第四步:看容器日志

bash 复制代码
docker logs --tail 50 <容器名>

日志里出现了 Permission denied 相关的报错。方向变了------这不是 MySQL 的问题,是操作系统权限的问题。

关键转折:为什么"能读不能写"?

把两个操作拆开看:

操作 本质上在做什么 需要什么权限
SELECT 查询 读取已有的 .ibd 文件 文件读权限(r)
CREATE TABLE 建表 在目录下创建新的 .ibd 文件 目录写权限(w)

当时目录和文件的权限是这样的:

  • 文件:644(-rw-r--r--)→ 其他人有读权限,所以 SELECT 能跑
  • 目录:755(drwxr-xr-x)→ 只有所有者能写,其他人没写权限,所以 CREATE TABLE 失败

那谁是"其他人"?这就是根因。

根因确认

回忆了一下最近做过什么操作------为了省去每次敲 sudo 的麻烦,我执行了:

bash 复制代码
sudo chown -R ubuntu:ubuntu /opt/resumeai

这一行命令,把整个数据目录的所有者改成了 ubuntu 用户(UID 1000)。

但 Docker 容器里 MySQL 官方镜像的 mysql 用户 UID 是 999。

Linux 判断权限不看用户名,看的是数字 UID。

容器内的 MySQL 进程(UID 999)到了宿主机目录(所有者 UID 1000)面前,被当成了一个陌生的"其他人"------有读权限,没有写权限。

这就是"能查不能建"的真正原因。


解决方案

bash 复制代码
# 1. 先确认容器内 mysql 用户的 UID
docker exec -it <容器名> id -u mysql
# 输出 999
​
# 2. 把数据目录改回容器内 MySQL 的 UID
sudo chown -R 999:999 /opt/resumeai/docker/resumeai/mysql/data
​
# 3. 重启容器
docker restart <容器名>

重新执行建表 SQL,通过。

如果你的 MySQL 镜像不是官方的(比如 MariaDB 或定制镜像),UID 可能不是 999,先查再改:

bash 复制代码
DOCKER_UID=$(docker exec <容器名> id -u mysql)
sudo chown -R ${DOCKER_UID}:${DOCKER_UID} /path/to/data

这件事教会我的

Linux 权限的 3 个核心认知

1. Linux 认的是数字 UID,不是用户名。

宿主机上的 ubuntu(UID 1000)和容器里的 mysql(UID 999),在系统眼里就是两个完全不同的人。就算你把容器里的用户也改成叫 ubuntu,UID 不同照样没权限。

2. 目录权限 ≠ 文件权限。

文件权限控制的是"能不能读/写这个文件的内容";目录权限控制的是"能不能在这个目录下创建、删除、重命名文件"。两者是独立的。

3. Docker 挂载卷的权限,由宿主机文件的 UID 决定。

容器内进程看到的权限,不是容器自己定义的,而是宿主机上那个文件/目录的 UID/GID 决定的。这是 Docker 数据卷最容易踩的坑。

以后怎么避免

不想每次输 sudo?正确做法是配免密,不是动目录权限:

ini 复制代码
sudo visudo
# 添加:
ubuntu ALL=(ALL) NOPASSWD: /usr/bin/docker

这样既能免密执行 docker 命令,又不会破坏数据目录的权限体系。

Docker 数据卷权限的黄金法则:

容器内进程的 UID = 宿主机数据目录所有者的 UID

记住这一条,90% 的 Docker 权限问题都不会遇到。


总结

维度 内容
问题 MySQL 建表报 1030,但查询正常
根因 chown 改了目录 UID,与容器内 MySQL UID 不匹配
解法 把目录所有者改回容器内 UID(通常 999)
教训 不要随意 chown Docker 挂载目录;用 sudo 免密替代

一个小时的排查,根源就是半年前我亲手敲的一行 chown。越是"我当时觉得没问题"的操作,越可能是后来问题的根源。

希望这篇帮你少走一次弯路。


如果这篇对你有帮助,点个赞再走呗 🙏 有 Docker 权限相关的踩坑经历,评论区聊聊?


相关推荐
打工仔折腾 AI17 分钟前
LLaMA 1 到 LLaMA 3 架构演进拆解:从 RoPE、GQA 到词表扩张
人工智能·后端·python·深度学习·langchain·llama
可乐鸡翅yeah_34 分钟前
HLS 分片过期清理,直播旧 TS 分片磁盘爆满问题处理
java·后端·spring·m3u8·m3u8在线·音视频在线播放
张彦峰ZYF1 小时前
加了锁不等于扛得住争用:synchronized、显式锁与 CAS 的语义分层、争用代价账本与选型判据
后端·同步设施·内置锁的四种状态与单向升级·可重入的由来与四条硬边界·显式锁的状态字段与等待队列·读写锁与邮戳锁·一次同步的开销账本
专业程序开发源1 小时前
SSM校园拍摄交流服务平台36936-计算机课程设计、毕业设计
java·spring boot·后端·python·elasticsearch·php·课程设计
Gopher_HBo1 小时前
zap采样器与性能优化内幕
后端
变量探索SEQVEC1 小时前
我埋了 8 个假文件,看谁会上钩:12 天 502 次扫描实录
后端
llqbzllll1 小时前
HashMap 的核心结构:从一次 put 看到扩容、桶迁移与树化边界
后端
晚安code1 小时前
设计模式入门:吃透 SOLID 原则与迪米特法则,再学 5 个高频模式
后端·设计模式
专业程序开发源4 小时前
django新闻推荐系统70655-计算机课程设计、毕业设计
java·javascript·spring boot·后端·python·django·课程设计
打工仔折腾 AI4 小时前
把 AI Agent 托管到家里电脑:UU远程端口映射与CLI实测记录
人工智能·后端·python·langchain·电脑·ai agent 实战