當您嘗試連線到 MySQL 伺服器時,伺服器會根據下列條件接受或拒絕連線
您的身分以及您是否可以透過提供適當的憑證來驗證它。
您的帳戶是否已鎖定或解除鎖定。
伺服器會先檢查憑證,然後檢查帳戶鎖定狀態。在任何一個步驟發生錯誤都會導致伺服器完全拒絕您的存取。否則,伺服器會接受連線,然後進入階段 2 並等待請求。
伺服器會使用 user 表中的欄位執行身分和憑證檢查,只有在滿足以下條件時才會接受連線
用戶端主機名稱和使用者名稱與某些
user表列中的Host和User欄位相符。有關允許的Host和User值的規則,請參閱 第 8.2.4 節,「指定帳戶名稱」。用戶端會提供該列中指定的憑證(例如,密碼),如
authentication_string欄位所示。憑證會使用plugin欄位中命名的驗證外掛程式進行解釋。該列表示帳戶已解除鎖定。鎖定狀態記錄在
account_locked欄位中,其值必須為'N'。可以使用CREATE USER或ALTER USER陳述式設定或變更帳戶鎖定。
您的身分基於兩個資訊
您的 MySQL 使用者名稱。
您連線的用戶端主機。
如果 User 欄位值為非空白,則傳入連線的使用者名稱必須完全符合。如果 User 值為空白,則符合任何使用者名稱。如果符合傳入連線的 user 資料表列的使用者名稱為空白,則該使用者會被視為沒有名稱的匿名使用者,而不是具有用戶端實際指定名稱的使用者。這表示在連線期間(即在第二階段)的所有進一步存取檢查都將使用空白的使用者名稱。
authentication_string 欄位可以為空白。這不是萬用字元,並不表示符合任何密碼。它表示使用者必須在不指定密碼的情況下連線。驗證用戶端的外掛程式實作的驗證方法可能會也可能不會使用 authentication_string 欄位中的密碼。在這種情況下,也可能使用外部密碼來驗證 MySQL 伺服器。
儲存在 user 資料表的 authentication_string 欄位中的非空白密碼值是加密的。MySQL 不會將密碼儲存為明文,讓任何人都能看到。相反地,嘗試連線的使用者所提供的密碼會被加密(使用帳戶驗證外掛程式實作的密碼雜湊方法)。然後,在連線過程中,會使用加密後的密碼來檢查密碼是否正確。這是在加密後的密碼永遠不會在連線中傳輸的情況下完成的。請參閱第 8.2.1 節,「帳戶使用者名稱和密碼」。
從 MySQL 伺服器的角度來看,加密後的密碼是真正的密碼,因此您絕對不應該讓任何人存取它。特別是,不要讓非管理使用者讀取 mysql 系統資料庫中的資料表。
下表顯示 user 資料表中 User 和 Host 值的各種組合如何應用於傳入連線。
User 值 |
Host 值 |
允許的連線 |
|---|---|---|
'fred' |
'h1.example.net' |
從 h1.example.net 連線的 fred |
'' |
'h1.example.net' |
從 h1.example.net 連線的任何使用者 |
'fred' |
'%' |
從任何主機連線的 fred |
'' |
'%' |
從任何主機連線的任何使用者 |
'fred' |
'%.example.net' |
從 example.net 網域中的任何主機連線的 fred |
'fred' |
'x.example.%' |
從 x.example.net、x.example.com、x.example.edu 等連線的 fred;這可能沒有用 |
'fred' |
'198.51.100.177' |
從具有 IP 位址 198.51.100.177 的主機連線的 fred |
'fred' |
'198.51.100.%' |
從 198.51.100 C 類子網路中的任何主機連線的 fred |
'fred' |
'198.51.100.0/255.255.255.0' |
與上一個範例相同 |
傳入連線的用戶端主機名稱和使用者名稱有可能與 user 資料表中的多列相符。上述範例集展示了這一點:顯示的幾個條目符合來自 h1.example.net 的 fred 的連線。
當有多個符合項時,伺服器必須決定要使用哪一個。它會按照以下方式解決此問題
每當伺服器將
user資料表讀取到記憶體時,它會對這些列進行排序。當用戶端嘗試連線時,伺服器會依排序順序搜尋這些列。
伺服器會使用第一個符合用戶端主機名稱和使用者名稱的列。
伺服器會使用排序規則,先排序具有最特定 Host 值的列
實體的 IP 位址和主機名稱是最特定的。
主機部分具有 IP 位址的帳戶具有以下特定順序
主機部分以 IP 位址給出的帳戶
CREATE USER 'user_name'@'127.0.0.1'; CREATE USER 'user_name'@'198.51.100.44';主機部分以使用 CIDR 表示法的 IP 位址給出的帳戶
CREATE USER 'user_name'@'192.0.2.21/8'; CREATE USER 'user_name'@'198.51.100.44/16';主機部分以使用子網路遮罩的 IP 位址給出的帳戶
CREATE USER 'user_name'@'192.0.2.0/255.255.255.0'; CREATE USER 'user_name'@'198.51.0.0/255.255.0.0';
模式
'%'表示「任何主機」,且最不特定。空字串
''也表示「任何主機」,但在'%'之後排序。
非 TCP(socket 檔案、具名管道和共用記憶體)連線會被視為本機連線,如果存在任何此類帳戶,則會比對 localhost 的主機部分,否則會比對符合 localhost 的萬用字元主機部分(例如,local%、l%、%)。
將 '%' 視為等同於 localhost 的處理方式已過時;您應該預期此行為將從未來版本的 MySQL 中移除。
具有相同 Host 值的列會先排序具有最特定 User 值的列。空白的 User 值表示「任何使用者」,且最不特定,因此對於具有相同 Host 值的列,非匿名使用者會在匿名使用者之前排序。
對於具有同等特定 Host 和 User 值的列,順序是不確定的。
若要瞭解其運作方式,假設 user 資料表如下所示
+-----------+----------+-
| Host | User | ...
+-----------+----------+-
| % | root | ...
| % | jeffrey | ...
| localhost | root | ...
| localhost | | ...
+-----------+----------+-當伺服器將資料表讀取到記憶體時,它會使用剛描述的規則對這些列進行排序。排序後的結果如下
+-----------+----------+-
| Host | User | ...
+-----------+----------+-
| localhost | root | ...
| localhost | | ...
| % | jeffrey | ...
| % | root | ...
+-----------+----------+-當用戶端嘗試連線時,伺服器會搜尋排序後的列,並使用找到的第一個符合項。對於來自 localhost 的 jeffrey 連線,資料表中的兩列符合:Host 和 User 值為 'localhost' 和 '' 的列,以及值為 '%' 和 'jeffrey' 的列。 'localhost' 列在排序順序中首先出現,因此這是伺服器使用的列。
這是另一個範例。假設 user 資料表如下所示
+----------------+----------+-
| Host | User | ...
+----------------+----------+-
| % | jeffrey | ...
| h1.example.net | | ...
+----------------+----------+-排序後的資料表如下所示
+----------------+----------+-
| Host | User | ...
+----------------+----------+-
| h1.example.net | | ...
| % | jeffrey | ...
+----------------+----------+-第一列符合來自 h1.example.net 的任何使用者的連線,而第二列符合來自任何主機的 jeffrey 的連線。
一種常見的誤解是認為,對於給定的使用者名稱,當伺服器嘗試尋找連線的符合項時,會先使用明確命名該使用者的所有列。這是不正確的。前面的範例說明了這一點,其中來自 h1.example.net 的 jeffrey 連線首先比對的是沒有使用者名稱的列,而不是將 'jeffrey' 作為 User 欄位值的列。因此,jeffrey 會被驗證為匿名使用者,即使他在連線時指定了使用者名稱。
如果您能夠連線到伺服器,但您的權限與您預期的不符,則您可能正在被驗證為其他帳戶。若要找出伺服器用於驗證您的帳戶,請使用 CURRENT_USER() 函數。(請參閱第 14.15 節,「資訊函數」。)它會以 格式傳回一個值,指出符合的 user_name@host_nameuser 資料表列中的 User 和 Host 值。假設 jeffrey 連線並發出以下查詢
mysql> SELECT CURRENT_USER();
+----------------+
| CURRENT_USER() |
+----------------+
| @localhost |
+----------------+這裡顯示的結果表示符合的 user 資料表列具有空白的 User 欄位值。換句話說,伺服器將 jeffrey 視為匿名使用者。
診斷驗證問題的另一種方法是列印出 user 資料表,並手動排序它,以查看首先進行符合項的位置。