MySQL 常见报错速查

开发中常遇到的 MySQL 报错信息,快速定位原因和解决方案。

ERROR 1045 (28000): Access denied for user 'xxx'@'xxx' (using password: YES)

出现场景:连接 MySQL 或执行需要权限的操作时

原因:密码错误、用户不存在、或用户的 host 不匹配当前连接来源

解决方案:

  1. 确认密码是否正确:注意 -p 后不要有空格直接跟密码,或回车后输入
  2. 检查用户是否存在:SELECT user, host FROM mysql.user WHERE user = 'xxx';
  3. 检查 host 是否匹配:'user'@'localhost' 和 'user'@'%' 是不同用户
  4. 重置密码:ALTER USER 'user'@'host' IDENTIFIED BY 'newpassword';
  5. 如果是 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 限制了连接来源

解决方案:

  1. 检查 MySQL 是否运行:systemctl status mysql
  2. 启动 MySQL 服务:systemctl start mysql
  3. 检查端口监听:ss -tlnp | grep 3306
  4. 检查 bind-address 配置:grep bind-address /etc/mysql/mysql.conf.d/mysqld.cnf(改为 0.0.0.0 允许远程)
  5. 检查防火墙:ufw allow 3306 或 firewall-cmd --add-port=3306/tcp --permanent
  6. 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 等操作引用表时

原因:表名拼写错误、未切换到正确的数据库、表已被删除、或大小写敏感问题

解决方案:

  1. 确认当前数据库:SELECT DATABASE(); 然后 SHOW TABLES;
  2. 检查表名拼写:SHOW TABLES LIKE '%order%';
  3. 切换到正确的数据库:USE ecommerce;
  4. 检查大小写:Linux 下 MySQL 表名默认区分大小写,确认 lower_case_table_names 配置
  5. 如果表被误删:从备份恢复,或检查 binlog 是否可以恢复

预防:SQL 中使用 database.table 全限定名避免歧义;表名统一用小写加下划线命名

ERROR 1062 (23000): Duplicate entry 'xxx' for key 'PRIMARY' / 'uk_xxx'

出现场景:INSERT 或 UPDATE 数据时违反唯一约束

原因:插入或更新的数据在主键或唯一索引列上与已有数据重复

解决方案:

  1. 查看冲突的数据:SELECT * FROM table WHERE unique_column = 'xxx';
  2. 使用 INSERT ... ON DUPLICATE KEY UPDATE 实现存在则更新:INSERT INTO t (id, name) VALUES (1, 'new') ON DUPLICATE KEY UPDATE name = 'new';
  3. 使用 INSERT IGNORE 忽略冲突行(不报错但也不插入)
  4. 使用 REPLACE INTO 替换已有记录(先删后插,注意会改变自增 ID)
  5. 如果是批量导入数据,先清理重复数据再导入

预防:插入前用 SELECT 检查是否存在;业务层做幂等设计;使用 ON DUPLICATE KEY UPDATE 处理并发场景

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

出现场景:执行 UPDATE、DELETE 或 SELECT ... FOR UPDATE 时等待行锁超时

原因:其他事务持有目标行的锁且长时间未释放(可能是慢查询、未提交的事务或死锁)

解决方案:

  1. 查看当前锁等待情况:SELECT * FROM information_schema.INNODB_LOCK_WAITS;(MySQL 5.7)或 SELECT * FROM performance_schema.data_lock_waits;(MySQL 8.0)
  2. 查看阻塞的事务:SHOW ENGINE INNODB STATUS; 找到 LATEST DETECTED DEADLOCK 部分
  3. 找到并终止阻塞进程:SHOW PROCESSLIST; 然后 KILL <blocking_thread_id>;
  4. 检查是否有未提交的事务:SELECT * FROM information_schema.INNODB_TRX WHERE trx_state = 'RUNNING';
  5. 增加锁等待超时时间(临时):SET innodb_lock_wait_timeout = 120;

预防:事务尽量短小,避免在事务中做耗时操作;大批量更新分批执行;保持事务中 SQL 的加锁顺序一致避免死锁