mysql 系統資料庫包含數個授權表,其中包含使用者帳戶及其所擁有的權限的相關資訊。本節說明這些表格。如需有關系統資料庫中其他表格的資訊,請參閱第 7.3 節「mysql 系統綱要」。
此處的討論說明授權表的底層結構,以及伺服器在與用戶端互動時如何使用其內容。然而,您通常不會直接修改授權表。當您使用諸如 CREATE USER、GRANT 和 REVOKE 等帳戶管理陳述式來設定帳戶並控制每個帳戶可用的權限時,會間接發生修改。請參閱第 15.7.1 節「帳戶管理陳述式」。當您使用此類陳述式執行帳戶操作時,伺服器會代表您修改授權表。
不建議使用諸如 INSERT、UPDATE 或 DELETE 等陳述式直接修改授權表,且後果自負。伺服器可以自由忽略因這類修改而變得格式錯誤的列。
對於任何修改授權表的操作,伺服器都會檢查表格是否具有預期的結構,如果沒有,則會產生錯誤。若要將表格更新為預期的結構,請執行 MySQL 升級程序。請參閱第 3 章升級 MySQL。
這些 mysql 資料庫表格包含授權資訊
user: 使用者帳戶、靜態全域權限和其他非權限欄位。global_grants: 動態全域權限。db: 資料庫層級權限。tables_priv: 表格層級權限。columns_priv: 欄位層級權限。procs_priv: 預存程序和函數權限。proxies_priv: 代理使用者權限。default_roles: 預設使用者角色。role_edges: 角色子圖的邊緣。password_history: 密碼變更記錄。
有關靜態和動態全域權限之間差異的資訊,請參閱 靜態與動態權限。)
在 MySQL 9.0 中,授權表格使用 InnoDB 儲存引擎且具有交易性。在 MySQL 9.0 之前,授權表格使用 MyISAM 儲存引擎且不具有交易性。授權表格儲存引擎的這種變更,使得帳戶管理語句(例如 CREATE USER 或 GRANT)的行為也能隨之變更。以前,指定多個使用者的帳戶管理語句可能對某些使用者成功,對其他使用者失敗。現在,每個語句都是交易性的,如果發生任何錯誤,則對所有指定的使用者都成功或回滾且沒有任何效果。
每個授權表格都包含範圍欄位和權限欄位
範圍欄位決定表格中每列的範圍;也就是說,列所套用的內容。例如,
user表格中,Host和User的值為'h1.example.net'和'bob'的列,套用於從主機h1.example.net連接到伺服器,且指定使用者名稱為bob的用戶端進行的驗證連線。同樣地,db表格中,Host、User和Db欄位值為'h1.example.net'、'bob'和'reports'的列,套用於bob從主機h1.example.net連線以存取reports資料庫的情況。tables_priv和columns_priv表格包含範圍欄位,指出每列套用的表格或表格/欄位組合。procs_priv範圍欄位指出每列套用的預存常式。權限欄位指出表格列授予的權限;也就是說,允許執行的操作。伺服器會合併各種授權表格中的資訊,以形成使用者權限的完整描述。第 8.2.7 節,「存取控制,階段 2:請求驗證」描述了此規則。
此外,授權表格可能包含用於範圍或權限評估以外用途的欄位。
伺服器會以如下方式使用授權表格
user表格的範圍欄位決定是否拒絕或允許連入連線。對於允許的連線,user表格中授予的任何權限表示使用者的靜態全域權限。此表格中授予的任何權限都套用於伺服器上的所有資料庫。警告因為任何靜態全域權限都被視為所有資料庫的權限,所以任何靜態全域權限都允許使用者查看所有資料庫名稱,透過
SHOW DATABASES或檢查INFORMATION_SCHEMA的SCHEMATA表格,除了那些在資料庫層級受到部分撤銷限制的資料庫。global_grants表格列出目前指派給使用者帳戶的動態全域權限。對於每一列,範圍欄位決定哪個使用者擁有權限欄位中命名的權限。db表格的範圍欄位決定哪些使用者可以從哪些主機存取哪些資料庫。權限欄位決定允許的操作。在資料庫層級授予的權限適用於資料庫和資料庫中的所有物件,例如表格和預存程式。tables_priv和columns_priv表格與db表格類似,但更精細:它們適用於表格和欄位層級,而不是資料庫層級。在表格層級授予的權限適用於表格及其所有欄位。在欄位層級授予的權限僅適用於特定欄位。procs_priv表格適用於預存常式(預存程序和函數)。在常式層級授予的權限僅適用於單一程序或函數。proxies_priv表格指出哪些使用者可以作為其他使用者的代理人,以及使用者是否可以將PROXY權限授予其他使用者。default_roles和role_edges表格包含有關角色關係的資訊。password_history表格保留先前選擇的密碼,以限制密碼重複使用。請參閱 第 8.2.15 節,「密碼管理」。
伺服器在啟動時將授權表格的內容讀取到記憶體中。您可以透過發出 FLUSH PRIVILEGES 陳述式或執行 mysqladmin flush-privileges 或 mysqladmin reload 命令來告知它重新載入表格。對授權表格的變更會在 第 8.2.13 節,「權限變更生效時間」中指示的時間生效。
當您修改帳戶時,最好驗證您的變更是否具有預期的效果。若要檢查特定帳戶的權限,請使用 SHOW GRANTS 陳述式。例如,若要判斷授予使用者名稱和主機名稱值為 bob 和 pc84.example.com 的帳戶的權限,請使用此陳述式
SHOW GRANTS FOR 'bob'@'pc84.example.com';若要顯示帳戶的非權限屬性,請使用 SHOW CREATE USER
SHOW CREATE USER 'bob'@'pc84.example.com';
伺服器會在存取控制的第一階段和第二階段使用 mysql 資料庫中的 user 和 db 表格(請參閱 第 8.2 節,「存取控制和帳戶管理」)。user 和 db 表格中的欄位如下所示。
表格 8.4 user 和 db 表格欄位
| 表格名稱 | user |
db |
|---|---|---|
| 範圍欄位 | Host |
Host |
User |
Db |
|
User |
||
| 權限欄位 | Select_priv |
Select_priv |
Insert_priv |
Insert_priv |
|
Update_priv |
Update_priv |
|
Delete_priv |
Delete_priv |
|
Index_priv |
Index_priv |
|
Alter_priv |
Alter_priv |
|
Create_priv |
Create_priv |
|
Drop_priv |
Drop_priv |
|
Grant_priv |
Grant_priv |
|
Create_view_priv |
Create_view_priv |
|
Show_view_priv |
Show_view_priv |
|
Create_routine_priv |
Create_routine_priv |
|
Alter_routine_priv |
Alter_routine_priv |
|
Execute_priv |
Execute_priv |
|
Trigger_priv |
Trigger_priv |
|
Event_priv |
Event_priv |
|
Create_tmp_table_priv |
Create_tmp_table_priv |
|
Lock_tables_priv |
Lock_tables_priv |
|
References_priv |
References_priv |
|
Reload_priv |
||
Shutdown_priv |
||
Process_priv |
||
File_priv |
||
Show_db_priv |
||
Super_priv |
||
Repl_slave_priv |
||
Repl_client_priv |
||
Create_user_priv |
||
Create_tablespace_priv |
||
Create_role_priv |
||
Drop_role_priv |
||
| 安全性欄位 | ssl_type |
|
ssl_cipher |
||
x509_issuer |
||
x509_subject |
||
plugin |
||
authentication_string |
||
password_expired |
||
password_last_changed |
||
password_lifetime |
||
account_locked |
||
Password_reuse_history |
||
Password_reuse_time |
||
Password_require_current |
||
User_attributes |
||
| 資源控制欄位 | max_questions |
|
max_updates |
||
max_connections |
||
max_user_connections |
user 表格的 plugin 和 authentication_string 欄位儲存驗證外掛程式和認證資訊。
伺服器使用帳戶列的 plugin 欄位中命名的外掛程式來驗證該帳戶的連線嘗試。
plugin 欄位不得為空。在啟動時,以及在執行 FLUSH PRIVILEGES 時的執行階段,伺服器會檢查 user 表格列。對於任何 plugin 欄位為空的列,伺服器會將此形式的警告寫入錯誤記錄檔
[Warning] User entry 'user_name'@'host_name' has an empty plugin
value. The user will be ignored and no one can login with this user
anymore.若要將外掛程式指派給缺少外掛程式的帳戶,請使用 ALTER USER 陳述式。
password_expired 欄位允許 DBA 使帳戶密碼過期,並要求使用者重設其密碼。預設的 password_expired 值為 'N',但可以使用 ALTER USER 陳述式設定為 'Y'。在帳戶密碼過期後,直到使用者發出 ALTER USER 陳述式以建立新的帳戶密碼之前,該帳戶在後續連線到伺服器中執行的所有操作都會產生錯誤。
雖然可以將過期的密碼設定為其目前值來「「重設」」,但較好的做法是選擇不同的密碼。DBA 可以透過建立適當的密碼重複使用原則來強制執行不重複使用。請參閱 密碼重複使用原則。
password_last_changed 是一個 TIMESTAMP 欄位,指出上次變更密碼的時間。僅當使用 MySQL 內建驗證外掛程式 (sha256_password 或 caching_sha2_password) 的帳戶時,該值才不為 NULL。對於其他帳戶,例如使用外部驗證系統進行驗證的帳戶,該值為 NULL。
password_last_changed 會由 CREATE USER、ALTER USER 和 SET PASSWORD 陳述式更新,也會由建立帳戶或變更帳戶密碼的 GRANT 陳述式更新。
password_lifetime 指示帳戶密碼的存續期間,以天為單位。如果密碼超過其存續期間(使用 password_last_changed 欄位評估),當客戶端使用該帳戶連線時,伺服器會將該密碼視為已過期。大於零的 N 值表示密碼必須每 N 天變更一次。值為 0 會停用自動密碼過期功能。如果值為 NULL(預設值),則會套用全域過期原則,如 default_password_lifetime 系統變數所定義。
account_locked 指示帳戶是否已鎖定(請參閱 第 8.2.20 節「帳戶鎖定」)。
Password_reuse_history 是帳戶的 PASSWORD HISTORY 選項值,若為預設歷史記錄則為 NULL。
Password_reuse_time 是帳戶的 PASSWORD REUSE INTERVAL 選項值,若為預設間隔則為 NULL。
Password_require_current 對應於帳戶的 PASSWORD REQUIRE 選項值,如下表所示。
表 8.5 允許的 Password_require_current 值
| Password_require_current 值 | 對應的 PASSWORD REQUIRE 選項 |
|---|---|
'Y' |
PASSWORD REQUIRE CURRENT |
'N' |
PASSWORD REQUIRE CURRENT OPTIONAL |
NULL |
PASSWORD REQUIRE CURRENT DEFAULT |
User_attributes 是一個 JSON 格式的欄位,用於儲存未儲存在其他欄位中的帳戶屬性。INFORMATION_SCHEMA 會透過 USER_ATTRIBUTES 表格公開這些屬性。
User_attributes 欄位可能包含下列屬性
additional_password:第二個密碼(如果有的話)。請參閱雙密碼支援。Restrictions:限制清單(如果有的話)。限制由部分撤銷操作新增。屬性值是一個元素陣列,每個元素都有Database和Restrictions鍵,分別指示受限資料庫的名稱及其上的適用限制(請參閱第 8.2.12 節「使用部分撤銷的權限限制」)。Password_locking:失敗登入追蹤和臨時帳戶鎖定的條件(如果有的話)(請參閱失敗登入追蹤和臨時帳戶鎖定)。Password_locking屬性會根據CREATE USER和ALTER USER陳述式的FAILED_LOGIN_ATTEMPTS和PASSWORD_LOCK_TIME選項更新。屬性值是一個雜湊,其中包含failed_login_attempts和password_lock_time_days鍵,指示已為該帳戶指定的選項值。如果缺少鍵,則其值隱含為 0。如果鍵值隱含或明確為 0,則會停用相應的功能。multi_factor_authentication:mysql.user系統表格中的列具有plugin欄位,指示驗證外掛程式。對於單因素驗證,該外掛程式是唯一的驗證因素。對於雙因素或三因素形式的多因素驗證,該外掛程式對應於第一個驗證因素,但必須儲存其他資訊以供第二個和第三個因素使用。multi_factor_authentication屬性會保留此資訊。multi_factor_authentication值是一個陣列,其中每個陣列元素都是一個雜湊,使用下列屬性描述驗證因素plugin:驗證外掛程式的名稱。authentication_string:驗證字串值。passwordless:一個旗標,表示該使用者是否旨在不使用密碼的情況下使用(僅使用安全權杖作為驗證方法)。requires_registration:一個旗標,定義使用者帳戶是否已註冊安全權杖。
第一個和第二個陣列元素描述多因素驗證因素 2 和 3。
如果沒有任何屬性適用,則 User_attributes 為 NULL。
範例:具有第二個密碼且已部分撤銷資料庫權限的帳戶在欄位值中具有 additional_password 和 Restrictions 屬性
mysql> SELECT User_attributes FROM mysql.User WHERE User = 'u'\G
*************************** 1. row ***************************
User_attributes: {"Restrictions":
[{"Database": "mysql", "Privileges": ["SELECT"]}],
"additional_password": "hashed_credentials"}若要判斷存在哪些屬性,請使用 JSON_KEYS() 函數
SELECT User, Host, JSON_KEYS(User_attributes)
FROM mysql.user WHERE User_attributes IS NOT NULL;若要擷取特定屬性(例如 Restrictions),請執行以下操作
SELECT User, Host, User_attributes->>'$.Restrictions'
FROM mysql.user WHERE User_attributes->>'$.Restrictions' <> '';以下是為 multi_factor_authentication 儲存的資訊範例
{
"multi_factor_authentication": [
{
"plugin": "authentication_ldap_simple",
"passwordless": 0,
"authentication_string": "ldap auth string",
"requires_registration": 0
},
{
"plugin": "authentication_webauthn",
"passwordless": 0,
"authentication_string": "",
"requires_registration": 1
}
]
}
在存取控制的第二階段中,伺服器會執行請求驗證,以確保每個客戶端都具有發出的每個請求的足夠權限。除了 user 和 db 授權表格外,對於涉及表格的請求,伺服器也可能會查詢 tables_priv 和 columns_priv 表格。後面的表格會在表格和欄位層級提供更精細的權限控制。它們具有下表所示的欄位。
表 8.6 tables_priv 和 columns_priv 表格欄位
| 表格名稱 | tables_priv |
columns_priv |
|---|---|---|
| 範圍欄位 | Host |
Host |
Db |
Db |
|
User |
User |
|
Table_name |
Table_name |
|
Column_name |
||
| 權限欄位 | Table_priv |
Column_priv |
Column_priv |
||
| 其他欄位 | Timestamp |
Timestamp |
Grantor |
Timestamp 和 Grantor 欄位會分別設定為目前時間戳記和 CURRENT_USER 值,但在其他方面未使用。
對於涉及預存常式的請求驗證,伺服器可能會查詢 procs_priv 表格,該表格具有下表所示的欄位。
表 8.7 procs_priv 表格欄位
| 表格名稱 | procs_priv |
|---|---|
| 範圍欄位 | Host |
Db |
|
User |
|
Routine_name |
|
Routine_type |
|
| 權限欄位 | Proc_priv |
| 其他欄位 | Timestamp |
Grantor |
Routine_type 欄位是一個 ENUM 欄位,其值為 'FUNCTION' 或 'PROCEDURE',以指示該列所參考的常式類型。此欄位可讓函數和同名的程序分別授予權限。
Timestamp 和 Grantor 欄位未使用。
proxies_priv 表格會記錄關於 Proxy 帳戶的資訊。它具有以下欄位
若要讓帳戶能夠將 PROXY 權限授予其他帳戶,它必須在 proxies_priv 表格中具有將 With_grant 設定為 1,並將 Proxied_host 和 Proxied_user 設定為指示可授予權限的帳戶或帳戶的列。例如,在 MySQL 安裝期間建立的 'root'@'localhost' 帳戶在 proxies_priv 表格中具有一列,可讓 ''@'' 授予 PROXY 權限,也就是說,可讓所有使用者和所有主機授予權限。這讓 root 可以設定 Proxy 使用者,以及將設定 Proxy 使用者的權限委派給其他帳戶。請參閱第 8.2.19 節「Proxy 使用者」。
global_grants 表格會列出目前指派給使用者帳戶的動態全域權限。該表格具有以下欄位
USER、HOST:授予權限的帳戶的使用者名稱和主機名稱。PRIV:權限名稱。WITH_GRANT_OPTION:帳戶是否可以將權限授予其他帳戶。
default_roles 表格會列出預設使用者角色。它具有以下欄位
HOST、USER:套用預設角色的帳戶或角色。DEFAULT_ROLE_HOST、DEFAULT_ROLE_USER:預設角色。
role_edges 表格會列出角色子圖形的邊緣。它具有以下欄位
FROM_HOST、FROM_USER:被授予角色的帳戶。TO_HOST、TO_USER:授予該帳戶的角色。WITH_ADMIN_OPTION:帳戶是否可以使用WITH ADMIN OPTION將角色授予和撤銷其他帳戶。
password_history 表格包含密碼變更的資訊。它具有以下欄位
Host、User:發生密碼變更的帳戶。Password_timestamp:發生密碼變更的時間。Password:新的密碼雜湊值。
password_history 資料表會為每個帳戶累積足夠的非空密碼,讓 MySQL 能夠根據帳戶密碼歷史長度和重複使用間隔進行檢查。當密碼變更嘗試發生時,會自動修剪超出這兩個限制的條目。
空密碼不計入密碼歷史記錄,並且可以隨時重複使用。
如果帳戶被重新命名,其條目也會被重新命名以匹配。如果帳戶被刪除或其身份驗證外掛程式被更改,其條目將被移除。
授權表中的範圍欄位包含字串。每個欄位的預設值為空字串。下表顯示每個欄位允許的字元數。
表 8.8:授權表範圍欄位長度
| 欄位名稱 | 最大允許字元數 |
|---|---|
Host, Proxied_host |
255 |
User, Proxied_user |
32 |
Db |
64 |
Table_name |
64 |
Column_name |
64 |
Routine_name |
64 |
Host 和 Proxied_host 值在儲存到授權表之前會轉換為小寫。
為了進行存取檢查,User、Proxied_user、authentication_string、Db 和 Table_name 值的比較會區分大小寫。Host、Proxied_host、Column_name 和 Routine_name 值的比較不區分大小寫。
user 和 db 資料表在單獨的欄位中列出每個權限,這些欄位被宣告為 ENUM('N','Y') DEFAULT 'N'。換句話說,每個權限都可以停用或啟用,預設為停用。
tables_priv、columns_priv 和 procs_priv 資料表將權限欄位宣告為 SET 欄位。這些欄位中的值可以包含資料表控制的任何權限組合。只有欄位值中列出的權限才被啟用。
表 8.9:Set 類型權限欄位值
| 表格名稱 | 欄位名稱 | 可能的 Set 元素 |
|---|---|---|
tables_priv |
Table_priv |
'Select'、'Insert'、'Update'、'Delete'、'Create'、'Drop'、'Grant'、'References'、'Index'、'Alter'、'Create View'、'Show view'、'Trigger' |
tables_priv |
Column_priv |
'Select'、'Insert'、'Update'、'References' |
columns_priv |
Column_priv |
'Select'、'Insert'、'Update'、'References' |
procs_priv |
Proc_priv |
'Execute'、'Alter Routine'、'Grant' |
只有 user 和 global_grants 資料表指定了管理權限,例如 RELOAD、SHUTDOWN 和 SYSTEM_VARIABLES_ADMIN。管理操作是對伺服器本身的操作,而不是特定於資料庫的操作,因此沒有理由在其他授權表中列出這些權限。因此,伺服器只需要查詢 user 和 global_grants 資料表,以判斷使用者是否可以執行管理操作。
FILE 權限也僅在 user 資料表中指定。它本身不是管理權限,但是使用者在伺服器主機上讀取或寫入檔案的能力與所存取的資料庫無關。
為了允許對 MySQL 授權表進行並行的 DML 和 DDL 操作,先前在 MySQL 授權表上取得資料列鎖定的讀取操作將以非鎖定讀取執行。在 MySQL 授權表上執行為非鎖定讀取的操作包括:
SELECT陳述式和其他透過聯結列表和子查詢從授權表讀取資料的唯讀陳述式,包括使用任何交易隔離等級的SELECT ... FOR SHARE陳述式。使用任何交易隔離等級,從授權表(透過聯結列表或子查詢)讀取資料但不修改它們的 DML 操作。
當從授權表讀取資料時不再取得資料列鎖定的陳述式,如果在執行時使用基於陳述式的複製,則會報告警告。
當使用 -binlog_format=mixed 時,從授權表讀取資料的 DML 操作會以資料列事件寫入二進位日誌,以使操作對於混合模式複製是安全的。
從授權表讀取資料的 SELECT ... FOR SHARE 陳述式會報告警告。對於 FOR SHARE 子句,授權表上不支援讀取鎖定。
使用 SERIALIZABLE 隔離等級執行且從授權表讀取資料的 DML 操作會報告警告。通常在使用 SERIALIZABLE 隔離等級時會取得的讀取鎖定,在授權表上不支援。