mysqldump 必须用 --compatible 参数才能兼容旧版 MySQL,否则新特性会导致报错;该参数可降级语法(如 mysql40、ansi),但不解决字符集、类型映射、时间戳语义、外键约束等跨库兼容问题。
导出时指定 --compatible 参数才能真正兼容旧版 MySQL
默认 mysqldump 生成的 sql 包含新版本特性(比如 with rollup、窗口函数注释、`utf8mb4_0900_as_cs` 排序规则),旧版 mysql 会直接报错退出。关键不是改字符集或删注释,而是用 --compatible 让 dump 主动降级语法。
-
--compatible=mysql40:禁用分区、视图、存储过程,用TYPE=MyISAM替代ENGINE= -
--compatible=ansi:转义关键字(如把order变成"order"),禁用反引号 - 多个模式可叠加:
--compatible=mysql40,ansi - 注意:
--compatible不影响字符集声明,仍需额外加--default-character-set=utf8避免utf8mb4报错
PostgreSQL 或 SQLite 导入时,字段类型必须手动映射
mysqldump 没有跨数据库导出模式,所谓“兼容”只是让 SQL 不报错,但语义可能失效。比如 TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP 在 PostgreSQL 中不存在对应语法,SQLite 更不支持默认函数。
- MySQL 的
ENUM和SET类型需转成TEXT或VARCHAR -
BIT(1)在 PostgreSQL 中要改成BOOLEAN,SQLite 改成INTEGER - 用
sed或perl批量替换比手改靠谱:sed 's/ENUM([^)]*)/TEXT/g' dump.sql - 别依赖
--skip-extended-insert来“方便修改”——它只拆 INSERT,不解决类型冲突
时间戳和时区处理最容易导致数据错乱
MySQL 5.6+ 默认启用 explicit_defaults_for_timestamp,而老版本默认行为不同;加上各数据库对 TIMESTAMP 是否自动转时区理解不一,导出后直接导入常出现时间偏移 8 小时或全变成 0000-00-00 00:00:00。
- 导出前确认源库时区:
SELECT @@time_zone, @@system_time_zone; - 加
--tz-utc=false禁用 UTC 转换,保留本地时间字面值 - 如果目标库是 PostgreSQL,把
TIMESTAMP全替换成TIMESTAMP WITHOUT TIME ZONE,否则可能被强转 - 避免用
NOW()或CURRENT_TIMESTAMP作为默认值导出——它们在其他系统里不被识别
外键和约束在目标库不生效时,别硬扛着开 FOREIGN_KEY_CHECKS=0
MySQL 的外键定义语法(CONSTRAINT `fk_name` FOREIGN KEY (`col`) REFERENCES `tbl` (`col`))在 PostgreSQL 中虽能解析,但约束名长度、引用动作(ON DELETE CASCADE)支持度不同;SQLite 则完全忽略外键定义(除非显式 PRAGMA foreign_keys = ON)。
- 先用
--skip-triggers --skip-routines --skip-events减少干扰项 - 导出时不带约束:
--skip-add-drop-table --no-create-info,先建表再单独加约束 - 检查目标库是否真支持该约束行为——比如 SQLite 的
ON DELETE SET NULL实际无效 - 最稳妥的做法:导出纯数据(
--no-create-info --skip-extended-insert),用目标库工具重新建模
真正麻烦的从来不是语法能不能跑通,而是 TIMESTAMP 字段值是否还是你存进去的那个时间,以及外键删掉一条记录时,到底有没有连带删掉关联行。这些得看目标库文档,不能靠 mysqldump 一个参数包打天下。











