MySQL 8.0 的 lower_case_table_names 值必须在首次初始化时固化,之后无法修改;若服务配置与数据字典值不一致(如报错 MY-011087),则启动失败,唯一解决方式是清空 datadir 并用 --lower-case-table-names=指定值重新初始化。

MySQL 8.0 跨版本迁移时,lower_case_table_names 配置不能“改了重启就生效”——它必须在数据目录首次初始化时就定死。你看到的报错 MY-011087,不是配置没写对,而是 MySQL 拒绝启动,因为服务端参数和数据字典记录值不一致。
为什么改完 lower_case_table_names=1 重启就报 MY-011087?
MySQL 8.0 的数据字典在 mysqld --initialize 阶段就把 lower_case_table_names 值固化进系统表了,之后任何修改(包括 SET GLOBAL、改 /etc/my.cnf、加启动参数)都会被忽略。日志里那句 Different lower_case_table_names settings for server ('1') and data dictionary ('0') 就是 MySQL 在告诉你:“你配的和我脑子里记的根本不是一回事,我不干”。
常见错误现象:
- 配置文件写了
lower_case_table_names=1,重启后SELECT @@lower_case_table_names返回1,但查表仍报Table doesn't exist - 用
mysqld --verbose --help | grep lower_case看到的值是1,但服务压根没起来,日志全是MY-011087 - Docker 容器第一次运行后,再进容器改
my.cnf,重启必崩
Docker 环境下必须用启动参数初始化,不能靠配置文件
Docker 启动 MySQL 8.0 容器时,--lower-case-table-names=1 必须作为命令行参数传给 mysqld,且必须在容器第一次写入数据前执行。配置文件(如 /etc/mysql/conf.d/custom.cnf)在这个阶段还没读取,或优先级低于命令行参数。
正确做法:
- 确保容器没有挂载已有非空
/var/lib/mysql目录(否则跳过初始化,直接加载旧字典) - 首次启动命令必须显式带参数:
docker run -d --name mysql8 -e MYSQL_ROOT_PASSWORD=123 -v /data:/var/lib/mysql -p 3306:3306 mysql:8.0 --lower-case-table-names=1 - 如果用了自定义配置文件,检查它是否覆盖了
lower_case_table_names;Docker 启动参数优先级高于配置文件,但前提是配置文件没在初始化前就被加载并触发校验
已有数据目录时,lower_case_table_names=1 不是“开启”,而是“重建”
你不能让旧表名自动变小写。MySQL 8.0 不提供在线转换工具。物理文件名(如 UserOrder.ibd)和数据字典里的元数据必须严格匹配,否则访问失败。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
安全路径只有两条:
-
全量重建:停服务 → 备份
mysqldump --all-databases→ 清空/var/lib/mysql→ 用--lower-case-table-names=1重新初始化 → 导入 -
逐表重命名:执行
RENAME TABLE `UserOrder` TO `userorder`(注意反引号包裹原名,否则语法错误)→ 同步更新所有 SQL、视图、存储过程、外键约束中的引用 → 改完后手动检查/var/lib/mysql/your_db/下文件名是否已变小写
别漏掉 SET FOREIGN_KEY_CHECKS = 0 再操作,否则外键会拦住 RENAME。
云数据库或无法清空数据的场景,只能改应用层
阿里云 RDS、腾讯云 CDB 等托管服务通常锁定 lower_case_table_names=1 且不允许修改。此时唯一可行的路是统一应用层 SQL 表名全部小写——这不是妥协,是必须遵守的数据契约。
容易被忽略的关键点:
-
mysqldump导出时若源库是lower_case_table_names=0,dump 文件里建表语句仍保留原始大小写(如CREATE TABLE `UserOrder`),导入到=1的目标库会自动转成小写,但应用代码里若还写UserOrder,就可能因 ORM 缓存或预编译 SQL 出问题 - 开发环境用 macOS(默认
=2)、测试环境用 Linux(默认=0)、生产环境又设成=1,这种混搭极易埋雷;最稳的做法是从开发第一天起就约定全部小写表名










