MySQL登錄驗證方式
前些天接到一個客戶發來的信息:自建MySQL
實例之後,使用mysql -uroot@'192.168.3.6'
無法登錄,密碼沒有問題;後麵將所有其他不相幹的mysql.user
表數據刪除後,可以正常登錄。
因為客戶並沒有保存詳細的登錄及報錯信息,導致完全複原客戶場景。
借這個機會好好說說MySQL
數據庫登錄驗證的步驟,在登錄遇到問題時提供參考。
當嚐試連接到MySQL server
時,服務器會根據用戶名、密碼來驗證您的身份。如果沒有,服務器將完全拒絕對您的訪問。否則,服務器接受連接,然後進入等待請求階段。
連接驗證階段
連接請求到達服務器之後,MySQL
會將用戶名、密碼、Host
參數信息與mysql.users.(user、password、host)
進行驗證。當完全匹配時,才允許登錄。
以用戶baiyang
為例,下表顯示了各種組合User
和Host
值,涵蓋了MySQL
登錄驗證的所有情況。
User 值 | Host 值 | 允許連接 |
---|---|---|
'baiyang' | 'h1.example.net' | baiyang,連接 h1.example.net |
'' | 'h1.example.net' | 任何用戶,連接 h1.example.net |
'baiyang' | '%' | baiyang,從任何主機連接 |
'' | '%' | 任何用戶,從任何主機連接 |
'baiyang' | '%.example.net' | baiyang,從example.net域中的任何主機連接 |
'baiyang' | 'x.example.%' | baiyang,從連接 x.example.net, x.example.com, x.example.edu,等; 這可能沒有用 |
'baiyang' | '172.19.65.170' | baiyang,從主機與IP地址進行連接 172.19.65.170 |
'baiyang' | '172.19.65.%' | baiyang,從172.19.65 C類子網中的任何主機連接 |
'baiyang' | '172.19.65.0/255.255.255.0' | 與上一個例子相同 |
上麵可以發現user.user
字段值baiyang
出現多次,但是對應的user.host
卻不重複;用戶連接請求怎麼與mysql.user
進行匹配呢?
下麵給出mysql
的做法:
1:每當數據庫加載mysql.user
數據後,會對表進行排序
2:當客戶端嚐試連接時,MySQL server
端按照排序順序進行匹配驗證
3:使用第一條用戶名和客戶端主機名匹配的行響應客戶端的請求
MySQL server
對mysql.user
怎麼排序的呢?
哪一行數據的mysql.host
越精確,哪一行數據越在前。
如當前mysql.user
的數據為:
root@localhost:test 02:51:53> select user,host from mysql.user where user = 'baiyang';
+---------+---------------+
| user | host |
+---------+---------------+
| baiyang | % |
| baiyang | 127.0.0.1 |
| baiyang | 172.19.151.9 |
| baiyang | localhost |
+---------+---------------+
4 rows in set (0.00 sec)
加載到MySQL server
後,順序發生了變化,其結果集可以用SQL來表示:
root@localhost:(none) 02:58:30> select user,host from mysql.user where user = 'baiyang' order by host desc;
+---------+---------------+
| user | host |
+---------+---------------+
| baiyang | localhost |
| baiyang | 172.19.151.9 |
| baiyang | 127.0.0.1 |
| baiyang | % |
+---------+---------------+
不管是從本地客戶端還是從遠程客戶端連接,都會按照上麵的排序規則進行驗證:匹配上的第一條用戶信息響應客戶端。
舉個例子:分別在本地、遠程客戶端訪問數據庫,查看匹配上的用戶到底是哪個。
本地連接
1:不指定 host
的連接
默認 host
為 localhost
,那麼客戶端是以 user='baiyang' host='localhost'
的連接方式去請求MySQL server
;mysql.user
中存在| baiyang | localhost |
的用戶信息,那麼將以此來做匹配。
# /mysql/bin/mysql -phahahehe -ubaiyang -e "SELECT CURRENT_USER();"
Warning: Using a password on the command line interface can be insecure.
+-------------------+
| CURRENT_USER() |
+-------------------+
| baiyang@localhost |
+-------------------+
2:指定 host='127.0.0.1'
的連接,客戶端是以 user='baiyang' host='127.0.0.1'
的連接方式去請求MySQL server
;mysql.user
中存在| baiyang | 127.0.0.1 |
的用戶信息,那麼將以此來做匹配。
# /mysql/bin/mysql -phahahehe -ubaiyang -h 127.0.0.1 -e "SELECT CURRENT_USER();"
Warning: Using a password on the command line interface can be insecure.
+-------------------+
| CURRENT_USER() |
+-------------------+
| baiyang@127.0.0.1 |
+-------------------+
遠程連接
MySQL Server
所在服務器、遠程客戶端均是阿裏雲ECS服務器
有公網和內網兩個IP
/ | 公網 | 內網 |
---|---|---|
MySQL Server | 139.224.x.x | 172.19.65.17 |
CLient | 101.132.x.x | 172.19.151.9 |
MySQL Server mysql.user
表中有
+---------+---------------+
| user | host |
+---------+---------------+
| baiyang | 172.19.151.94 |
| baiyang | % |
+---------+---------------+
兩個用於遠程連接的用戶信息,遠程登錄用戶認證方式如下:
1:139.224.x.x 是 MySQL Server
的公網IP,當使用公網IP進行連接時,客戶端的IP同為公網IP 101.132.x.x ,該IP在mysql.user
沒有精確匹配的host
,所以認證用戶為 baiyang@%
# mysql -h139.224.13.72 -ubaiyang -phahahehe -e "SELECT CURRENT_USER();" -P3308
+----------------+
| CURRENT_USER() |
+----------------+
| baiyang@% |
+----------------+
2:172.19.65.170 是MySQL Server
的內網IP,因此客戶端的IP同為內網IP 172.19.151.9,該IP在mysql.user
有精確匹配的host
,所以認證用戶為 baiyang@baiyang@172.19.151.9
# mysql -h172.19.65.170 -ubaiyang -phahahehe -e "SELECT CURRENT_USER();" -P3308
+-----------------------+
| CURRENT_USER() |
+-----------------------+
| baiyang@172.19.151.9 |
+-----------------------+
以上,隻要密碼是正確的,就能連接的上數據庫;若連接有問題,可以根據報錯信息、MySQL用戶登錄驗證方式來排查問題。
最後更新:2017-10-28 15:33:21