MySQL数据库最常见的6中故障的排除方法

1.MySQL无法启动

2.MySQL连接不上

3.MySQL打开文件失败

4.MySQL挂起(hung)

5.MySQL崩溃(crash)

6.忘记用户密码

1.MySQL无法启动

1.无法访问系统资源

2.参数设置错误

无法访问系统资源

检查访问文件和目录的权限 测试:

# sudo -u mysql touch /home/mysql/data/filename

有访问文件和目录的权限,但是仍然会被拒绝访问

mysql> system sudo -u mysql touch /home/mysql/data/a 
mysql> create table t1 (id int primary key,n varchar(10)) data directory='/home/mysql/data'; 
ERROR 1030(HY000):Got error 168 from storage engine 
原因:mysqld进程的访问被Linux的selinux或apparmor给阻止

系统资源被其它进程占用

# mysqld --no-defaults --console --user mysql
2020-11-03T03:36:07.519419Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.19)starting as process 21171
2020-11-03T03:36:07.740347Z 1 (ERROR] [MY-012574] nnoDB] Unable to lock ./ibdata1 error: 11
原因:另外一个 mysqld 进程已经启动并占用了对应的文件

查询 MySQL启动时调用参数文件的顺序

$ mysqld --verbose --help| grep "Default options "-A 1 
Default options are read from the following files in the given order: 
/etc/my.cnf /etc/mysql/my.cnf ~/.my.cnf

显示mysqld 程序将要调用的参数

$ mysqld --print-defaults 
usr/sbin/mysqld would have been started with the following arguments: 
.... 
这个命令和 my_print_defaults mysqld 完全是等价的,只不过后者的显示方式是一行一个参数

对可疑的参数进行调试

在mysqld 后加上第一个参数--no-defaults,这个参数的作用是通知 mysld 在启动的时候不要读任何参数文件;

第二个参数是--console,这个参数会把错误信息输出到屏幕上,这个参数带来的一个弊端是所有的信息都输出到屏幕上,让屏幕显得比较乱,但对于我们调试却是很方便的;

第三个参数是--log-error-verbosity=3,这个参数会显示详细的日志;

然后再在后面加上有把握的参数,可以一次只加一个参数,然后启动 mysqld,采用排除法逐步找出错误的参数

参数调试的例子

# mysqld --no-defaults --console --log-error-verbosity=3 --user mysql --gtid_mode=on
......
2020-11-03T07:14:21.632851Z 0 [ERROR][MY-010912] [Server] GTID_MODE = ON requiresENFORCE GTID CONSISTENCY = ON.
.......
需要我们同时设置参数GTID MODE和 ENFORCE GTID CONSISTENCY 同时为 on

2.MySQL连接不上

客户端连接 MySQL失败的三个原因

MySQL服务器上的进程 mysqld 没有正常运行

客户端不能和进程mysqld 通信

账户密码的问题

MySQL服务器上的进程mysqld 没有正常运行

遇到这种情况首先到服务器上看看 mysgld 进程是否活着,采用的命令是

mysqladmin ping 或 ps -ef l grep mysqld

客户端不能和进程mysqld 通信

进行网络连通的测试:

telnet localhost 3306

如果本地能通,再到客户端的机器上把 localhost 换成 MySQL 服务器的 ip 地址进行测试

如果不能通,通常有两种原因:

一种原因是 OS或网络的问题,或者是防火墙:

另一种原因是mysqld 自身根本没有侦听客户端的连接请求

mysqld启动后对于客户端的侦听的三种情况

使用参数 --skip-networking 跳过侦听客户端的网络连接

使用参数 --bind-address 后面增加对客户端访问IP 地址的限制

对客户端访问IP 地址的不进行限制

使用参数--skip-networking 跳过侦听客户端的网络连接

# mysqld --no-defaults --console --user mysql --skip-networking &
# netstat -plunt|grep 3306
#

使用参数--bind-address 后面增加对客户端访问IP 地址的限制

# mysqld --no-defaults --user mysql --bind-address=127.0.0.1 &
# netstat -plunt|grep 3306
tcp    0    0 127.0.0.1:3306    0.0.0.0:*    LISTEN    22767/mysqld
tcp6    0     0:::33060    :::*     LISTEN    22767/mysqld
# mysqld --no-defaults --user mysql --bind-address='192.168.17.40' &
# netstat -plunt|grep 3306
tcp    0    0 192.168.17.40:3306    0.0.0.0:*    LISTEN    23053/mysqld
tcp6    0    0:::33060    :::*    LISTEN    23053/mysqld

error log 记载信息的详细程度上由参数--log-error-verbosity进行控制的

默认为 2,设置为3可以记录更多的信息,这个参数可以联机设置

Permitted Message Priorities

log_error_verbosity Value

ERROR

1

ERROR,WARNING

2

ERROR,WARNING,INFORMATION

3

密码错误

root@scutech:~# mysql -uroot -perrorpassword
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
在MySQL的 errorlog 里有这样的记录:
2020-11-03T07:59:40.720835Z 7 [Note] [MY-010926] [Server] Access denied for user 'root'@'localhost' (using password: YES)
如果把参数 --log-error-verbosity 设置成的默认值 2 时是没有这个提示的,也就说没有 note类型的信息。

账户错误

ERROR 1130 (HY000): Host '192.168.17.149' is not allowed to connect to this MySQL server
注意账户错误时,提示是“is not allowed to connect to this MySQL server”,而密码错误时是“Access denied for user ”

账户错误问题解决

MySQL中的一个账户是由 user 和 host 两个部分组成,在 MySQL 中有个 mysql 数据库,里面有个user表,表中 Host和 User 为两个主键列 (primary key),唯一表示一个用户。像这种情况通常是 host 字段部分是 localhost,把它改成通配符"%"即可。

mysql> update mysql.user set host='%' where user='root';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> flush privileges;
Query OK, 0 rows affected (0.02 sec)

3.MySQL打开文件失败

MySQL打开文件失败相关的错误

shell> perror 23
OS error code 23: File table overflow
shell> perror 24
OS error code 24: Too many open files
shell> perror 11
OS error code 11: Resource temporarily unavailable

查看MySQL已经打开的文件数

OS 中统计已经打开的文件
 ls -l /proc/`pidof mysqld`/fd|wc
MySQL数据库里统计已经打开的文件数查看状态参数
 Open_table_definitions 和 Open_tables

解决打开文件数多的方法

一种是减少 MySQL同时打开的文件数量,例如减少参数 table_open_cache 或/和 max_connections。

另一种方法是增加 MySQL 可以打开的文件数量,即增加 MySQL 的参数open_files_limit。

参数open_files_limit

MySQL 启动时这个参数起作用,在运行的时候系统会自动调整,会根据下面两个公式选择其中一个大的数:

10 + max_connections +(table_open_cache* 2)

max_connections*5

MySQL8.0.19 版本之后就直接用操作系统的限制

Linux操作系统对打开文件数的限制

配置文件 /etc/security/limits.conf
检查进程的限制:
cat /proc/`pidof mysqld`/limits|grep "Max open files'

4.MySQL挂起(hung)

系统资源的瓶颈造成的MySQL数据库挂起

使用OS层的 top sar free iostat vmstat 等查看系统资源的瓶颈

检查MySQL数据库运行状态

$ mysqladmin -i 5 processlist status

检查Innodb引擎的状态

mysql> show engine innodb status \G

关注一下几个部分:
LATEST DETECTED DEADLOCK
TRANSACTIONS
FILE I/O

在主键上的update是行级锁,在其它键的update是表级锁

索引上的查询也是行级别的锁

解决死锁(deadlock)

临时解决,kill 造成死锁的连接:
for id in `mysqladmin processlist | grep -i locked | awk '{print $1}'` 
do
    mysqladmin kill ${id}
done
根本解决,修改应用
delete update 避免使用非索引字段为条件
避免批量 delete update

5.MySQL崩溃(crash)

检查MySQL数据库的启动时间

检查 MySQL 服务状态 $ service mysql status
检查 MySQL中的uptime 状态 mysql> show global status like 'uptime';
使用 ps 检查进程启动时间 $ ps -eo pid,user,args,etime|grep mysqld
检查 MySQL日志 找关键字“ready for connections”

kill 和 kill -9 杀死 mysqld 进程的区别

使用 kill -9 杀死 mysqld 进程系统会自动重新启动,而只使用 kill 命令则不会重新启动,因为执行 kill 命令,系统会发送一个SIGTERM 信号给 mysqld,MySQL数据库会正常关闭,日志中会出现类似下面的记录:
2020-10-26T09:06:48.435181Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.0.19) MySQL Community Server - GPL.
1

MySQL数据库 crash 的常见原因

MySQL数据库 crash 的最常见原因有两个

1.MySQL的 bug

2.MySQL申请系统资源失败或内存泄漏。

MySQL的 bug

MySQL数据库 crash 的最常见的一个原因当然是 MySQL 的bug。95%的 bug 都是和具体的sql 相关,通常是 MySQL crash 前执行的最后一个sql 有问题,因此定位 bug 时应打开 general query log,根据最后一个 sql 来查找线索。

MySQL的 bug 库(MySQL Bugs)

查找 MSQL申请系统资源失败或内存泄漏的根本原因

1.仔细阅读 MySQL的错误日志,这个日志里面的一些程序调试信息看起来很让人困惑,但静下心来仔细看,很多时候会找到线索:

2.打开 general query log,找到最后一个 sql 访问的表或索引,检查这个表或索引,如果有问题就重建,通常可以解决问题。

3.使用 strace、pstack、pmap、gdb 分析mysqld 的代码,可能需要打开 core dump;

4.使用CMake 的选项-DWITH_DEBUG=1 重新编译 mysqld,然后运行重新编译后的 mysqld查看trace 文件、error log 进行排错

mysqld 内存占用的计算

全局内存
innodb_buffer_pool_size innodb_log_buffer_size thread_cache_size table_open_cache table_definition_cache key_buffer_size
线程内存
binlog_cache_size thread_stack
单次操作内存
join_buffer_size read_buffer_size read_rnd_buffer_size tmp_table_size sort_buffer_size

内存占用参考值计算公式

SELECT (@@innodb_buffer_pool_size + @@innodb_log_buffer_size + @@key_buffer_size+ @@max_connections*(@@binlog_cache_size + @@thread_stack + @@read_buffer_size+ @@read_rnd_buffer_size + @@sort_buffer_size + @@join_buffer_size + @@tmp_table_size)/ 1024 /1024 AS MAX MEM MB;

临时释放缓存

echo 1> /proc/sys/vm/drop_caches

0:0是系统默认值,默认情况下表示不释放内存,由操作系统自动管理

1:释放页缓存

2:释放dentries和inodes

3:释放所有缓存

从长远看还是要修改对应的参数进行解决。

MySQL客户端的内存泄漏的现象

mysql: Out of memory at line 42, 'malloc.c'
mysql: needed 8136 byte (8k), memory in use: 12481367 bytes (12189k)
ERROR 2008: MySQL client ran out of memory

客户端收到的返回结果集太大的解决办法

1.检查正在运行的 SQL,看看您真的需要这么大的返回结果集吗?

2.允许 mysql 时加上 --quick 选项,这会减少客户端单次收到的返回集,但会增加 mysqld 的负载。

6.忘记用户密码

MySQL忘记root密码的两种解决方法

skip-grant-tables

init-file

启动mysqld的时候加上参数skip-grant-tables

在默认的参数文件中加上skip-grant-tables
root@infokist:/etc/mysql# service mysql restart
root@infokist:/etc/mysql# mysql
mysql> update mysql.user set authentication_string=password('dingjia') where user='root';
Query OK, 1 row affected, 1 warning (0.00 sec)
Rows matched:1 Changed:1 Warnings: 1
mysql> flush privileges;
Query OK, 0 rows affected (0.01 sec)

MySQL8 中的变化

加了 skip-grant-tables 参数后会自动加上skip-networking 不允许远程连接
移除了 PASSWORD() 函数
修改密码的方法是用 alter user 的命令修改密码,但注意要载入权限表后才能alter user
mysql> alter user root identified by 'dingjia';
ERROR 1290 (HY000): The MySQL server is running with the --skip-grant-tables option so itcannot execute this statement
mysql> flush privileges;
Query OK, 0 rows affected (0.07 sec)
mysql> alter user root@localhost identified by 'dingjia';
Query OK, 0 rows affected (0.02 sec)、

init-file方案

使用 -init-file 参数启动实例,类似: mysqld_safe --init-file=/tmp/chpw.sql&
在chpw.sql文件里面写上密码修改语句:
alter user 'root'@'localhost' dentified by 'dingjia';
实例启动成功后,密码即修改完毕
这种方法只会重启一次 MySQL实例,而且基本上不存在安全隐患

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐