MySQL 常见报错速查
开发中常遇到的 MySQL 报错信息,快速定位原因和解决方案。
ERROR 1045 (28000): Access denied for user 'xxx'@'xxx' (using password: YES)
出现场景:连接 MySQL 或执行需要权限的操作时
原因:密码错误、用户不存在、或用户的 host 不匹配当前连接来源
解决方案:
- 确认密码是否正确:注意 -p 后不要有空格直接跟密码,或回车后输入
- 检查用户是否存在:SELECT user, host FROM mysql.user WHERE user = 'xxx';
- 检查 host 是否匹配:'user'@'localhost' 和 'user'@'%' 是不同用户
- 重置密码:ALTER USER 'user'@'host' IDENTIFIED BY 'newpassword';
- 如果是 root 忘记密码:用 --skip-grant-tables 模式启动 MySQL 后重置
预防:使用配置文件 ~/.my.cnf 存储认证信息避免密码输错;创建用户时明确指定 host 范围
ERROR 2003 (HY000): Can't connect to MySQL server on 'host' (111) / ERROR 2002: Can't connect through socket
出现场景:客户端尝试连接 MySQL 服务器时
原因:MySQL 服务未启动、端口未监听、防火墙阻止、或 bind-address 限制了连接来源
解决方案:
- 检查 MySQL 是否运行:systemctl status mysql
- 启动 MySQL 服务:systemctl start mysql
- 检查端口监听:ss -tlnp | grep 3306
- 检查 bind-address 配置:grep bind-address /etc/mysql/mysql.conf.d/mysqld.cnf(改为 0.0.0.0 允许远程)
- 检查防火墙:ufw allow 3306 或 firewall-cmd --add-port=3306/tcp --permanent
- Socket 错误时检查 socket 文件路径:mysql -S /var/run/mysqld/mysqld.sock -u root -p
预防:配置 MySQL 开机自启:systemctl enable mysql;监控 MySQL 进程存活状态
ERROR 1146 (42S02): Table 'database.table_name' doesn't exist
出现场景:执行 SELECT、INSERT、UPDATE 等操作引用表时
原因:表名拼写错误、未切换到正确的数据库、表已被删除、或大小写敏感问题
解决方案:
- 确认当前数据库:SELECT DATABASE(); 然后 SHOW TABLES;
- 检查表名拼写:SHOW TABLES LIKE '%order%';
- 切换到正确的数据库:USE ecommerce;
- 检查大小写:Linux 下 MySQL 表名默认区分大小写,确认 lower_case_table_names 配置
- 如果表被误删:从备份恢复,或检查 binlog 是否可以恢复
预防:SQL 中使用 database.table 全限定名避免歧义;表名统一用小写加下划线命名
ERROR 1062 (23000): Duplicate entry 'xxx' for key 'PRIMARY' / 'uk_xxx'
出现场景:INSERT 或 UPDATE 数据时违反唯一约束
原因:插入或更新的数据在主键或唯一索引列上与已有数据重复
解决方案:
- 查看冲突的数据:SELECT * FROM table WHERE unique_column = 'xxx';
- 使用 INSERT ... ON DUPLICATE KEY UPDATE 实现存在则更新:INSERT INTO t (id, name) VALUES (1, 'new') ON DUPLICATE KEY UPDATE name = 'new';
- 使用 INSERT IGNORE 忽略冲突行(不报错但也不插入)
- 使用 REPLACE INTO 替换已有记录(先删后插,注意会改变自增 ID)
- 如果是批量导入数据,先清理重复数据再导入
预防:插入前用 SELECT 检查是否存在;业务层做幂等设计;使用 ON DUPLICATE KEY UPDATE 处理并发场景
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
出现场景:执行 UPDATE、DELETE 或 SELECT ... FOR UPDATE 时等待行锁超时
原因:其他事务持有目标行的锁且长时间未释放(可能是慢查询、未提交的事务或死锁)
解决方案:
- 查看当前锁等待情况:SELECT * FROM information_schema.INNODB_LOCK_WAITS;(MySQL 5.7)或 SELECT * FROM performance_schema.data_lock_waits;(MySQL 8.0)
- 查看阻塞的事务:SHOW ENGINE INNODB STATUS; 找到 LATEST DETECTED DEADLOCK 部分
- 找到并终止阻塞进程:SHOW PROCESSLIST; 然后 KILL <blocking_thread_id>;
- 检查是否有未提交的事务:SELECT * FROM information_schema.INNODB_TRX WHERE trx_state = 'RUNNING';
- 增加锁等待超时时间(临时):SET innodb_lock_wait_timeout = 120;
预防:事务尽量短小,避免在事务中做耗时操作;大批量更新分批执行;保持事务中 SQL 的加锁顺序一致避免死锁