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 能跑
  • 目录:755drwxr-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 权限相关的踩坑经历,评论区聊聊?


相关推荐
无相求码1 小时前
为什么 printf 可以接受任意数量参数?变长参数的底层真相
后端
郡杰1 小时前
Boot:MP|测验|结果封装|异常处理|前后联调|拦截器
后端
团团崽_七分甜1 小时前
后端基础概念 - 前端开发者指南(进程、线程、事务)
后端
倔强的石头_2 小时前
从5万次到日均2000万次调用:大模型推理服务的性能工程实践V2.1
后端
环境栈笔记2 小时前
多账号浏览器选型检查清单:Profile、权限、Session 和任务日志怎么评估
前端·人工智能·后端·自动化
shepherd1112 小时前
一次把 Spring MVC 文件上传参数“查没了”的排查:multipart、Filter 与 request body 的连环坑
java·spring boot·后端
mONESY3 小时前
Node.js fs 文件系统模块 四种读写方案全解析
javascript·后端
Larcher3 小时前
从回调地狱到优雅异步:Node.js 文件操作进化史
javascript·后端·架构
Java编程爱好者3 小时前
深入浅出Agent: Harness最全调研与原理解析(持续更新中)
后端