MySQL root密碼忘記,原來還有更優雅的解法!

一直以來,對於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 5.7的操做,若是是在5.6版本,修改的應該是password字段,而不是authentication_string。
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操做是不行的,由於此時的權限表還沒加載。可先經過flush privileges操做觸發權限表的加載,再執行alter user操做。

須要注意的是,經過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。

相關文章
相關標籤/搜索