权限不足是第一排查点,需检查并授予目标库insert和select权限,postgresql还需usage on schema;autocommit开启导致回滚无效,应显式begin;列序或字符集不一致易致静默错误,须显式指定字段名并核对建表语句。
复制表结构后 insert 报错:access denied for user
权限不足是第一排查点,不是“可能”,而是大概率就是它。mysql 或 postgresql 的账号默认不带跨库写入权限,哪怕你用 create table like 复制成功了,也不代表有目标库的 insert 权限。
实操建议:
- 检查当前用户对目标库的权限:
SHOW GRANTS FOR CURRENT_USER;,重点看是否含INSERT和SELECT(某些复制逻辑会隐式查源表) - 如果只给了
SELECT,补权限:GRANT INSERT ON `target_db`.* TO 'user'@'%'; FLUSH PRIVILEGES; - 注意:PostgreSQL 中需同时授予
USAGEon schema +INSERTon table;仅INSERT不够,schema 级权限缺失也会静默失败
INSERT ... SELECT 执行后数据消失,回滚没生效
常见于自动提交(autocommit)开启状态——语句一执行就落地,根本没进事务,所以 ROLLBACK 无效。这不是 bug,是预期行为。
实操建议:
- 先确认 autocommit 状态:
SELECT @@autocommit;(MySQL)或SHOW TRANSACTION ISOLATION LEVEL;(PG,但更要看 BEGIN 是否显式调用) - 必须手动开启事务:
BEGIN;→INSERT ... SELECT→COMMIT;或ROLLBACK; - 避免在应用层拼接 SQL 时漏掉
BEGIN,尤其 ORM 如 Django 的atomic装饰器未包裹整个操作链时,中间某步出错就无法回滚
用 mysqldump --no-data 复制结构,再 INSERT 却提示列数不匹配
表结构看似一致,但源表和目标表的列顺序、默认值、生成列(generated column)、虚拟列(virtual column)可能不同,INSERT ... SELECT * 严格按列序匹配,不看字段名。
实操建议:
- 别用
*,显式写出字段名:INSERT INTO t2 (a,b,c) SELECT a,b,c FROM t1; - 检查两表字段顺序:
DESCRIBE t1;和DESCRIBE t2;对比,尤其注意TIMESTAMP默认值、AUTO_INCREMENT字段位置 - MySQL 8.0+ 中若含
STORED列,dump 不会导出其定义,但插入时仍参与列计数,容易错位
复制后数据量对不上,但没报错
静默丢数据往往发生在字符集或排序规则不一致时:比如源表是 utf8mb4_unicode_ci,目标表是 utf8mb4_general_ci,某些特殊字符在插入时被截断或转成 ?,而 MySQL 默认不报错(除非 SQL mode 含 STRICT_TRANS_TABLES)。
实操建议:
- 对比两张表的建表语句:
SHOW CREATE TABLE t1;和SHOW CREATE TABLE t2;,逐项核对CHARSET、COLLATE、ROW_FORMAT、ENGINE - 临时启用严格模式测试:
SET sql_mode = 'STRICT_TRANS_TABLES';再跑一次插入,看是否爆出Data too long for column类错误 - 用
CHECKSUM TABLE t1, t2;(MySQL)快速验证行级一致性,比 COUNT 更可靠
最容易被忽略的是:目标表加了 NOT NULL 约束但源表对应字段允许 NULL,插入时 NULL 值被强制转成默认值(如 0 或空字符串),既不报错也不提醒,数据就悄悄变了。










