安裝完MySQL后,我們通常添加擁有相應權限的普通用戶用來訪問數據庫。在使用普通用戶(假設為tom)本地登錄數據庫的時候,經常會出現無法登錄的情況,但是從其他的mysql客戶端卻可以登錄。在本地使用tom用戶不輸入密碼可以登陸成功。
登陸成功后執行如下命令
SELECT USER(), CURRENT_USER();
+-------------------------+-----------------------+
| USER() | CURRENT_USER() |
+-------------------------+-----------------------+
| tom@localhost | @localhost |
+-------------------------+-----------------------+
> USER()函數返回你在客戶端登陸時指定的用戶名和主機名
> CURRENT_USER()函數返回的是MySQL使用授權表中的哪個用戶來認證你的登錄請求
上述結果表明使用'tom'@'localhost'這個賬戶登錄數據庫(因為在本地登陸時沒指定主機,默認是以localhost登錄),但是數據庫使用的是''@'localhost'這個賬戶來進行登錄認證,而''@'localhost'這個匿名用戶是沒有密碼的,因此輸入空密碼登錄成功。但是登錄后,所對應的用戶的匿名用戶。
一般在MySQL在安裝完畢后,使用mysql_install_db這個腳本生成授權表,會默認創建''@'localhost'這個匿名用戶。正是因為這個匿名用戶,影響了其他用戶從本地登錄的認證。
MySQL是如何進行用戶身份認證呢?
一、當用戶從客戶端請求登陸時,MySQL將授權表中的條目與客戶端所提供的條目進行比較,包括用戶的用戶名,密碼和主機。授權表中的Host字段是可以使用通配符作為模式進行匹配的,如test.example.com, %.example.com, %.com和%都可以匹配test.example.com這個主機。授權表中的User字段不允許使用模式匹配,但是可以有一個空字符的用戶名代表匿名用戶,並且空字符串可以匹配所有的用戶名,就像通配符一樣。 當user表中的Host和User有多個值可以匹配客戶端提供的主機和用戶名時,MySQL將user表讀入內存,並且按照一定規則排序,按照排序規則讀取到的第一個匹配客戶端用戶名和主機名的條目對客戶端進行身份驗證。
二、排序規則:對於Host字段,按照匹配的精確程度進行排序,越精確的排序越前,例如當匹配test.example.com這個主機時, %.example.com比%.com更精確,而test.example.com比%.example.com更精確。對於User字段,非空的字符串用戶名比空字符串匹配的用戶名排序更靠前。 User和Host字段都有多個匹配值,MySQL使用主機名排序最前的條目,在主機名字段相同時再選取用戶名排序更前的條目。因此,如果User和Host字段都有多個匹配值,主機名最精確匹配的條目被用戶對用戶進行認證。
mysql> select host,user from mysql.user;
+--------------------------+-------+
| host | user |
+--------------------------+-------+
| % | tom |
| 127.0.0.1 | root |
| ::1 | root |
| localhost | root |
| localhost | |
| promote.cache-dns.local | |
| promote.cache-dns.local | root |
+---------------------------+-------+
根據上面的匹配規則以及用戶查詢結果:
使用tom在本機登錄數據庫時,不指定-h參數默認為localhost主機登錄,而在MySQL中有兩個匹配的條目:'tom'@'%' 和 ''@'localhost'
(匿名用戶能夠匹配的原因上面說過,空字符串可以匹配所有的用戶名),根據MySQL認證時的排序規則,第一個條目的用戶名排序更前,第二個條目的主機名更精確排序更前。而MySQL會優先使用主機名排序第一的條目進行身份認證,因此''@'localhost'被用戶對客戶端進行認證。所以只有使用匿名用戶的空密碼才能登錄進數據庫。
解決的方法:刪除匿名用戶(僅僅為了安全也有這個必要)
為什么root用戶不會受影響,而只有普通用戶不能從本地登錄?
因為mysql_install_db腳本會在授權表中生成'root'@'localhost'這個賬戶。同樣的,使用root登錄MySQL 時,'root'@'localhost'和''@'localhost'都能匹配登錄的賬戶,但是根據排序規則,主機名相同,而用戶名非空字符串優先,因此'root'@'localhost'這個條目的排序更靠前。使用root本地登錄是不會被匿名用戶遮蓋。
本文轉載自http://www.linuxidc.com/Linux/2015-03/115164.htm,僅作學習記錄以備查閱,稍作整理。