本節書摘來自異步社區出版社《MySQL排錯指南》一書中的第1章,第1.9節,作者:【美】Sveta Smirnova(斯維特 斯米爾諾娃),更多章節內容可以訪問云棲社區“異步社區”公眾號查看。
1.9 許可問題
MySQL有復雜的權限方案,這使得你可以精確地設置哪些用戶和主機可以或不可以執行這個或那個操作。從5.5版本開始,MySQL也有了可插拔式的身份驗證模式。
盡管它有很多優勢,但是這個方案很復雜。例如,讓user1@hostA、user2@hostA和user1@hostB不同會很容易混淆它們的權限。當用戶名相同而主機名變化的時候更是如此。
MySQL允許在對象和連接層面設置訪問規則。可以限制某個用戶對于特定的表、列等的訪問權限。
用戶通常會遇到兩類權限問題:
應該有權限連接到服務器的用戶無法連接,或者沒有權限的用戶可以連接;
用戶可以連接到服務器,但是無法使用他們本應該可以訪問的對象,或者可以訪問他們無權訪問的對象。
在解決這些問題之前,應該確認你是否可以連接到服務器。
當你作為解決問題的用戶成功連接到服務器之后(后面的章節將討論無法連接的情況),執行以下查詢:
USER()函數會返回當用戶連接到服務器時使用的連接參數。這些參數通常為指定的用戶名和運行客戶端的主機名。CURRENT_USER()函數會返回從權限表中選擇的與訪問權限相關的用戶名和主機名對。mysqld用這些用戶名和主機名對來檢查數據庫對象訪問權限。通過比較這些函數的結果,可以找到mysqld使用的權限和預期不同的原因。一個典型的問題是對主機名使用通配符%:
如果此時我以sveta身份連接并嘗試創建一個表,我就會獲得下面的錯誤:
該問題在于,MySQL服務器認為sveta是sveta@localhost,而不是通配符:
如果你不理解為什么選擇一臺或另一臺主機,可以進行如下查詢:
MySQL在表中按照從訪問最多的主機到訪問最少的主機的順序對行進行排序,然后使用第一個找到的值。因此,它把我當作sveta@localhost用戶進行連接,此時該用戶沒有CREATE權限。
USER()、CURRENT_USER()函數和“SELECT user, host FROM mysql.user ORDER BY host DESE”查詢語句是遇到權限問題時的首選。
另一種權限問題是你無法作為指定用戶進行連接。在這種情況下,通常可以從錯誤消息中了解問題產生的原因,錯誤消息一般如下所示:
在看到這條消息以后,你了解了用戶憑證。作為root超級用戶進行連接,然后檢查該用戶是否存在以及是否擁有所需權限:
在這個輸出信息中,你可以看到用戶'sveta'@'localhost'僅僅對book數據庫有權限,而對books數據庫沒有權限。現在,可以修復這個錯誤:賦予sveta@localhost用戶必要的權限。
前面的示例討論用戶缺失必要權限的情況。對于用戶被授予過多權限的情況也可以同樣處理;僅需要移除不必要的權限。
警告 警告
MySQL的權限與其管控對象是分離的:這意味著當你賦予某用戶權限時mysqld 不會檢查其是否存在,同時當授權對象被刪除時也不會移除相應權限。這樣做的好處是允許我們預先授予必要的權限,但同時也有可能在不經意的使用中帶來潛在的問題。
作為最佳實踐,我推薦你仔細學習MySQL的權限工作機制。尤其是在你想要在用戶對象級別授予權限的時候,因為你需要理解在一個級別授權是如何影響其他授權的。同樣,對于撤消權限情形也一樣重要,甚至更重要,因為如果你以為已經撤消了某個權限但它依然存在,這就會造成意外的訪問。
[1] 版本5.6.3開始,也可以在UPDATE和DELETE上使用EXPLAIN方法,不過把語句轉換成SELECT查詢仍然有效,因為你可以方便地檢查和操作實際的結果集,而不是僅使用EXPLAIN命令。這尤其適用于復雜的JOIN操作,尤其是當EXPLAIN輸出的檢查的行比實際更新的行還要多的時候。
[2] 你可以在http://dev.mysql.com/doc/refman/5.5/en/c.html找到關于C API的詳細描述。
[3] 第5章將詳細介紹如何解決復制失敗的問題,因此這里不再詳細解釋。
[4] MySQL企業級備份(MEB)以前也稱作InnoDB熱備份,是InnoDB表進行在線熱備份和其他存儲引擎的表進行在線備份的一個工具。第7章將討論備份的方法。
本文僅用于學習和交流目的,不代表異步社區觀點。非商業轉載請注明作譯者、出處,并保留本文的原始鏈接。