這幾天在MySQL新建用戶後,出現訪問拒絕的問題,錯誤碼為ERROR 1045(28000)。在網上搜索了很久,找到了很多解決辦法,但很遺憾的是這麼多辦法沒有一個能解決該問題。雖然出現的錯誤碼28000很多人都遇到過,但原因也有所不同,有的是mysql.user表中沒有信息,有的是root用戶沒有密碼(那就不用密碼登錄),而使用mysql-5.6.19時,mysql.user有用戶信息,root用戶沒有密碼,采用的方法是root用戶登錄時輸入空密碼,登錄成功。使用root用戶創建測試用test,密碼為test,語句如下:
grant all onlogdb.* to test identified by ‘test’;
在命令行輸入mysql -u test –p,輸入密碼test,出現下面的錯誤信息,詳細該錯誤信息很多人在使用MySQL時都遇到過。
ERROR 1045 (28000):Access denied for user 'test'@'localhost' (using password: YES)
解決方法是用root用戶再創建用戶test,密碼test,唯一不同的是指定test登錄的主機為localhost,如下:
grant all onlogdb.* to test@'localhost' identified by 'test';
再次使用test用戶登錄MySQL,成功,如下所示:
使用root用戶登錄MySQL,查看user表中的用戶信息如下,可以發現存在兩個test用戶,host的字段分別為%和localhost,就是前面創建的兩個用戶。
在MySQL中%表示可以在任何主機上登錄MySQL數據庫,那為什麼還需要明確創建登錄主機為localhost的用戶呢?這涉及到MySQL安裝時的初始化用戶,匿名用戶以及連接驗證策略等,下面進行深入的分析。
在安裝MySQL時,會默認初始化一些用戶,比如root用戶,以及host字段為localhost,user字段為空的用戶。User字段為空的用戶即為匿名用戶,該用戶的密碼也為空,任何人都可以使用匿名用戶登錄MySQL數據庫,但可以做的事情卻是有限的,比如在命令行直接輸入mysql登錄,可以查看匿名用戶對哪些數據庫有權限:
\
通過上面的圖片可以發現,匿名用戶僅對information_schema和test數據庫有權限。而匿名用戶又是如何影響其他用戶登錄,進而出現28000錯誤的呢?當試圖連接MySQL數據庫時,數據庫根據提供的身份和密碼決定是否接受連接請求,身份由兩部分組成:用戶名和客戶端主機(即輸入mysql命令的主機)。由於host字段中的%匹配任何主機或者host字段包含通配符,就可能出現多個匹配行,服務器必須決定匹配哪一個,解決方案如下:
服務器將user表中的數據讀入內存中,按照host和user字段對行進行排序。
當客戶端試圖連接時,服務器查找已排序的行並使用第一個匹配客戶端主機和用戶名的行,user字段為空表示可以匹配任何用戶。
找到匹配行後,在驗證密碼是否一致,如果一致則登錄成功。
根據上面描述的規則,通過示例來演示為什麼必須要創建test@localhost用戶,才能在本地登錄成功。對user表進行排序的結果如下圖所示:
當未創建test@localhost時,該表不包含第一行的記錄。用戶test登錄時,則會匹配到第四行的記錄:host為localhost,user為空,因為user為空可以匹配任何用戶,再去驗證密碼不成功登錄失敗。或者不使用密碼登錄,還是匹配到第四行,但驗證密碼成功,然而匿名用戶只對information_schema和test數據庫有權限,使用其它數據庫時也會失敗,如下所示: