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}'`
domysqladmin 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实例,而且基本上不存在安全隐患