一直以来,对于MySQL root密码的忘记,觉得只有一种解法-skip-grant-tables。mysql
问了下群里的大咖,第一反应也是skip-grant-tables。经过搜索引擎简单搜索了下,不管是百度,抑或Google,只要是用中文搜索,首页都是这种解法。可见这种解法在某种程度上已经占据了使用者的心智。下面具体来看看。sql
skip-grant-tables的解法vim
首先,关闭实例安全
这里,只能经过kill mysqld进程的方式。socket
注意:不是mysqld_safe进程,也切忌使用kill -9。ide
# ps -ef |grep mysqld root 6220 6171 0 08:14 pts/0 00:00:00 /bin/sh bin/mysqld_safe --defaults-file=my.cnf mysql 6347 6220 0 08:14 pts/0 00:00:01 /usr/local/mysql57/bin/mysqld --defaults-file=my.cnf --basedir=/usr/local/mysql57 --datadir=/usr/local/mysql57/data --plugin-dir=/usr/local/mysql57/lib/plugin --user=mysql --log-error=slowtech.err --pid-file=slowtech.pid --socket=/usr/local/mysql57/data/mysql.sock --port=3307 root 6418 6171 0 08:17 pts/0 00:00:00 grep --color=auto mysqld # kill 6347
使用--skip-grant-tables参数,重启实例函数
# bin/mysqld_safe --defaults-file=my.cnf --skip-grant-tables --skip-networking &
设置了该参数,则实例在启动过程当中会跳过权限表的加载,这就意味着任何用户都能登陆进来,并进行任何操做,至关不安全。this
建议同时添加--skip-networking参数。其会让实例关闭监听端口,天然也就没法创建TCP链接,而只能经过本地socket进行链接。搜索引擎
MySQL8.0就是这么作的,在设置了--skip-grant-tables参数的同时会自动开启--skip-networking。spa
修改密码
# mysql -S /usr/local/mysql57/data/mysql.sock mysql> update mysql.user set authentication_string=password('123456') where host='localhost' and user='root'; Query OK, 0 rows affected, 1 warning (0.00 sec) Rows matched: 1 Changed: 0 Warnings: 1 mysql> flush privileges; Query OK, 0 rows affected (0.00 sec)
update mysql.user set password=password('123456') where host='localhost' and user='root';
而在MySQL 8.0.11版本中,这种方式基本不可行,由于其已移除了PASSWORD()函数及再也不支持SET PASSWORD ... = PASSWORD ('auth_string')语法。
不难发现,这种方式的可移植性实在太差,三个不一样的版本,就前后经历了列名的改变,及命令的不可用。
下面,介绍另一种更通用的作法,仍是在skip-grant-tables的基础上。
与上面不一样的是,其会先经过flush privileges操做触发权限表的加载,再使用alter user语句修改root用户的密码,如:
# bin/mysql -S /usr/local/mysql57/data/mysql.sock mysql> alter user 'root'@'localhost' identified by '123'; ERROR 1290 (HY000): The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement mysql> flush privileges; Query OK, 0 rows affected (0.00 sec) mysql> alter user 'root'@'localhost' identified by '123'; Query OK, 0 rows affected (0.00 sec)
须要注意的是,经过alter user修改密码只适用于MySQL5.7和8.0,若是是MySQL 5.6,此处可写成
update mysql.user set password=password('123456') where host='localhost' and user='root';
最后重启实例
mysql> shutdown; # bin/mysqld_safe --defaults-file=my.cnf &
须要注意的是,若是在启动的过程当中没有指定--skip-networking参数,无需重启实例。但在网上看到的绝大多数方案,都是没有指定该参数,但重启了实例,实在没有必要。
下面对这个方案作个总结:
1. 若是只添加了--skip-grant-tables,修改完密码后,其实无需重启,执行flush privileges便可。
2. 从安全角度出发,建议加上--skip-networking。但因其是静态参数,将其剔除掉须要重启实例。
3. 加上--skip-networking,虽然能够屏蔽掉TCP链接,但对于本地其它用户,只要有socket文件的可读权限,都能无密码登陆。仍是存在安全隐患。
4. 不建议经过update的方式修改密码,更通用的实际上是alter user。
更优雅的解法
相对于skip-grant-tables方案,咱们来看看另一种更优雅的解法,其只会重启一次,且基本上不存在安全隐患。
首先,依旧是关闭实例
其次,建立一个sql文件
写上密码修改语句
# vim init.sql alter user 'root'@'localhost' identified by '123456';
最后,使用--init-file参数,启动实例
# bin/mysqld_safe --defaults-file=my.cnf --init-file=/usr/local/mysql57/init.sql &
实例启动成功后,密码即修改完毕~
若是mysql实例是经过服务脚原本管理的,除了建立sql文件,整个操做可简化为一步。
# service mysqld restart --init-file=/usr/local/mysql57/init.sql
注意:该操做只适用于/etc/init.d/mysqld这种服务管理方式,不适用于RHEL 7新推出的systemd。