根本原因是lower_case_table_names配置导致表名大小写匹配失败:linux默认为0(区分大小写),而macos/windows为1(不区分);需检查该变量值、show tables实际输出及information_schema中表名,跨平台迁移时须统一大小写。

MySQL 报错 Table 'xxx' doesn't exist 但表明明存在
根本原因往往不是表真丢了,而是数据库名或表名在查询时和实际存储不一致。Linux 下 MySQL 默认开启 lower_case_table_names=0,意味着表名严格区分大小写;而 Windows 和 macOS 默认是 1(忽略大小写)。如果你在开发机(macOS)建了 user_info,却在 Linux 服务器上执行 SELECT * FROM User_Info,就会直接报错。
- 先查当前设置:
SHOW VARIABLES LIKE 'lower_case_table_names'; - 值为
0:表名按创建时的大小写存储和匹配,mytable≠MyTable - 值为
1:所有表名转小写存储,查询时自动转小写匹配,最宽松 - 值为
2(少见):表名以创建时大小写存储,但比较时转小写 —— 这个模式下CREATE TABLE MyTable存成MyTable,但SELECT ... FROM mytable也能命中
用 SHOW TABLES 看到的表名和你写的对不上
这不是幻觉。当 lower_case_table_names=0 时,SHOW TABLES 显示的就是磁盘上真实的文件名(比如 UserLog.sql 对应表 UserLog),而你 SQL 里写的 userlog 或 userLog 就会找不到。
- 进对应数据库后,直接运行
SHOW TABLES;,注意观察输出里的实际拼写(包括大小写) - 不要依赖 IDE 自动补全的表名 —— 它可能缓存了旧名,或基于错误配置做了推测
- 如果用命令行连接,可加
-A参数禁用自动补全,避免干扰判断 - 检查
information_schema.tables中的table_name字段:SELECT table_name FROM information_schema.tables WHERE table_schema = 'your_db';,这个结果不受客户端影响
跨平台迁移后突然找不到表
从 macOS 导出 SQL 再导入到 Linux 是高发场景。导出时如果用了 mysqldump --databases,默认不会显式指定数据库名大小写;但导入时,如果目标 MySQL 的 lower_case_table_names=0,而 dump 文件里建表语句写的是 CREATE TABLE UserOrder,那它就只能用完全一致的大小写访问。
- 迁移前确认两端
lower_case_table_names值是否一致,不一致就别硬导 - 若必须迁移,导出前先统一转小写:用
mysqldump --skip-extended-insert --compact+ 脚本批量替换CREATE TABLE `XxX`→CREATE TABLE `xxx` - 导入后立刻验证:
USE your_db; SHOW TABLES;,逐个比对大小写 - 别指望改完配置重启就能“修复”已有表 ——
lower_case_table_names是启动参数,修改后需重新初始化数据目录,否则表文件名和元数据仍不匹配
SQL 里写死的数据库名也得小心大小写
很多人只盯着表名,忘了数据库名本身也可能被区分大小写。尤其在多租户、分库场景下,SELECT * FROM tenant_A.users 在 lower_case_table_names=0 的机器上,如果数据库实际叫 tenant_a,照样报错。
- 检查数据库是否存在且大小写一致:
SHOW DATABASES LIKE 'tenant_A'; - 用反引号包裹数据库名和表名是稳妥做法:
SELECT * FROM `tenant_A`.`users`;,但这不能绕过文件系统级的大小写限制 - 连接字符串里的
database=参数同样受此影响,应用层配置也要核对 - PHP 的
mysqli_select_db()、Python 的cursor.execute("USE xxx")都遵循同一套规则
事情说清了就结束。最麻烦的不是改配置,是线上已有表名混着大小写,又不敢停服重命名。











