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 小时前
ontainer App】Container App无法从Container Registries 拉取镜像 - 报错 Forbidden
后端·python·flask
程序员cxuan2 小时前
DeepSeek-V4-Flash 正式版来了!这次提升有点夸张。
人工智能·后端·程序员
小杍随笔4 小时前
2025年Rust GUI框架实战万字避坑指南
开发语言·后端·rust
geovindu4 小时前
CSharp: LogHelper
开发语言·后端·c#·.net
fliter5 小时前
Go设计取舍之一: goroutine 为什么保持匿名、无状态
后端
fliter5 小时前
Go设计取舍之二: maps.Keys和Values为什么返回迭代器
后端
热心市民lcj5 小时前
Spring Boot 整合 Caffeine 本地缓存实战
spring boot·后端·缓存
Revolution615 小时前
Nest.js 是什么:怎样用它写出第一个后端接口
后端·node.js·nestjs
aiopencode5 小时前
SwiftUI Introspect生产环境完全指南:为什么它是安全可靠的选择
后端·ios
shengjk15 小时前
x86架构发展史:从8086到x86-64,一文看懂40多年CPU指令集如何改变世界
后端