最近在折騰wordpress部落格,連接配接MySQL資料庫時提示拒絕通路。經過排查,解決了問題。這裡記錄下解決問題的方案,以及解決的思路。如有遇到類似問題的讀者可以參考下。
用wordpress搭部落格,資料庫采用MySQL。為了調試友善,建立賬戶
my_account
,允許它從任意主機通路資料庫。
CREATE USER `my_account`@'%' IDENTIFIED BY 'my_password';
Copy 修改 wp-config.php 相應配置,注意
DB_HOST
設定為
127.0.0.1
。
define('DB_USER', 'my_account'); // 賬号
define('DB_PASSWORD', 'my_password'); // 密碼
define('DB_HOST', '127.0.0.1'); // 資料服務位址
部署到雲伺服器上,本地浏覽器通路部落格,提示資料庫拒絕通路(本地連接配接遠端資料沒問題),以下為錯誤日志。
ERROR 1045 (28000): Access denied for user 'my_account'@'localhost' (using password: YES)`
簡單排查後,解決了問題,這裡記錄下解決方案,以及出錯的原因。
解決方案
1、方案一:删除 mysql.user表 中,Host字段為 localhost 的匿名賬号(賬戶名為空)。
2、方案二:建立 my_account@localhost 賬戶,用于本地連接配接資料庫。
筆者采用了方案 一。
首先,确認下 mysql.user 表中是否存在匿名賬戶。
MariaDB [(none)]> SELECT User, Host from mysql.user WHERE Host = 'localhost' AND User = '';
+------+-----------+
| User | Host |
+------+-----------+
| | localhost |
+------+-----------+
1 row in set (0.00 sec)
接着,删除相應匿名賬戶,再次嘗試登陸,成功。
MariaDB [(none)]> DROP USER ''@'localhost';
Query OK, 0 rows affected (0.00 sec)
問題分析
為什麼匿名賬戶會導緻資料庫連接配接失敗?
需要對MySQL的賬戶建立、用戶端連接配接校驗有一定的了解。
建立MySQL賬戶
基礎文法如下:
CREATE USER 賬戶名@主機 IDENTIFIED BY 密碼;
注意點:(以下用 User 指代賬戶名,Host 指代 主機)
- Host 表示 允許賬戶從哪台主機通路資料庫。主要用于做安全限制,可以是 主機名、IP位址、%(通配符);
- User 允許重複,隻要 Host 是不同的就行。
- 當 Host 設定為 % 時,表示允許從任意主機連接配接資料庫。
比如,存在兩個xiaoming賬戶,一個允許從本機連接配接資料庫,一個允許從 14.215.177.39 連接配接資料庫。
MariaDB [(none)]> SELECT User, Host FROM mysql.user WHERE User = 'xiaoming';
+---------+---------------+
| User | Host |
+---------+---------------+
| xiaoming | 14.215.177.39 |
| xiaoming | localhost |
+---------+---------------+
2 rows in set (0.00 sec)
匿名賬戶
也就是 User 為空的賬戶,可以比對任意使用者名。如下指令建立了匿名賬戶。
CREATE USER ''@'localhost' IDENTIFIED BY 'pwd3';
身份校驗
資料庫伺服器收到用戶端連接配接,首先會進行身份校驗,将 User、Host、Password 字段,跟 mysql.user 表裡的記錄進行比較,确認是否合法賬戶。
這裡有個問題:如果 mysql.user表 中存在多條比對記錄,該以哪條記錄為準?
答案是“優先級”。大緻規則如下:
- 首先,檢查 Host 字段。如果有多個 Host 符合條件,則選擇比對度最高的記錄(IP位址 > 通配符%)。
- 其次,檢查 User 字段。如果有多個 User 符合條件,則選擇比對度最高的記錄。匿名使用者可以比對任何使用者,是以比對度最低。
優先級比對例子
舉例,假設本地資料庫有如下兩個賬戶(Password字段實際非明文)。
+------------+-----------+-----------+
| User | Host | Password |
+------------+-----------+-----------+
| my_account | % | 123 |
| | localhost | 456 |
+------------+-----------+-----------+
運作如下指令,最終登入的賬戶,比對的是 第2條 記錄。(讀者可自行嘗試,輸入密碼123登入失敗,輸入456登入成功)
mysql -u my_account -p
為什麼呢?回顧下比對的優先級。
- 首先,檢查 Host 字段。localhost、% 都符合要求。localhost 比對度高于 %,是以比對到第2條記錄。
- 接着,檢查 User 字段。第2條記錄是匿名賬戶,可比對任意User值,是以,第2條記錄符合要求。
是以,雖然賬戶 my_account 的 Host字段 為%,但是在本地(資料庫所在主機)連接配接資料庫時,因為上述規則的存在,MySQL 會認為你是用匿名賬戶在登入。
my_account 跟匿名賬戶的密碼是不同的,是以密碼校驗不通過,拒絕通路。
寫在後面
因匿名使用者存在,導緻本地連接配接資料庫拒絕連接配接,這個問題很常見,有不少人認為這是MySQL的設計缺陷,比如
這裡了解了MySQL的身份驗證邏輯,遇到類似問題也就有思路了。關于%通配符,比對優先級,上文并沒有詳細展開,感興趣的讀者可以自行檢視官方文檔。
另外,MySQL拒絕通路的原因有多種,讀者應具體問題具體分析。
如有錯漏,敬請指出。