文章目录
账号控制与账户管理
权限表
mysql
数据库中包含了一些权限表,这些表包含了有关用户账户以及其拥有的权限信息。本节将描述这些表。关于系统数据库中其他表的信息,请参见The mysql System Schema
这里的讨论描述了授予表的底层结构,以及服务器在与客户机交互时如何使用它们的内容。但是,通常不直接修改授予表。当您使用帐户管理语句(如CREATE USER、GRANT
和REVOKE
)来设置帐户并控制每个帐户可用的权限时,修改就间接发生了。当您使用这样的语句来执行帐户操作时,服务器将代表您修改授予表。
授予表概述
这些mysql
据库包含权限信息:
user
:用户账号、全局权限和其他非权限列。global_grants
:动态全局权限。db
:数据库级别的权限。tables_priv
:表级别的权限。column_priv
:列级别的权限。procs_priv
:存储过程和函数权限。proxies_priv
:代理用户权限。default_roles
:默认用户角色。role_edges
:password_history
:历史更改过的密码。
在 MySQL 8.0 中,授权表使用 InnoDB
存储引擎并且是事务性的。在 MySQL 8.0 之前,授权表使用 MyISAM
存储引擎并且是非事务性的。这种授权表存储引擎的更改允许对帐户管理语句(如CREATE USER
或grant
)的行为进行相应的更改。以前,命名多个用户的帐户管理语句对于某些用户可能成功,而对于其他用户可能失败。现在,每个语句都是事务性的,要么对所有命名用户成功,要么回滚,如果发生任何错误,则无效。
每个授权表包含范围列和权限列:
-
范围列确定表中每一行的范围;也就是说,该行适用的上下文。例如,
user
表中Host
和User
列值为'h1.example.net'
和'bob'
,那么该行用于验证指定用户名为bob
的客户端从hosth1 .example.net
到服务器的连接。类似的,当bob
用户从主机h1.example.net
连接并访问report
数据库的时候,db
表中Host、User
和db
列值为'h1.example.net'、'bob'、reports
的行将被应用。tables_priv
和columns_priv
表包含范围列,指示每行适用的表或表/列组合。procs_priv
范围列指示每行适用的存储例程。 -
权限列告诉MySQL服务表行授予哪些权限;也就是说,它允许执行哪些操作。服务器将各种授权表中的信息结合起来,形成用户权限的完整描述。 Access Control, Stage 2: Request Verification,描述了这方面的规则。
此外,授权表可能包含用于范围或权限评估以外目的的列。
服务器以下列方式使用授权表:
-
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
表保留以前用过的密码,以启用对密码重用的限制。
服务器在启动时将授权表的内容读入内存。您可以通过发出 FLUSH PRIVILEGES
语句或执行 mysqladmin flush-privileges 或 mysqladmin reload
命令来告诉它重新加载表。对权限表的更改将按照When Privilege Changes Take Effect中的说明使其生效。
当您修改帐户时,最好验证您的更改是否具有预期效果。要检查给定帐户的权限,请使用 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
表(请参阅Access Control and Account Management)。此处显示了 user
和 db
表中的列。
Table Name | user | db |
---|---|---|
Scope columns | Host | Host |
User | Db | |
User | ||
Privilege columns | 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 | ||
Security columns | 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 | ||
Resource control columns | max_questions | |
max_updates | ||
max_connections | ||
max_user_connections |
user
表的plugin
和 authentication_string
列存储身份验证插件和凭据信息。
服务器使用帐户行中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
语句来建立新的帐户密码。
password_last_changed
是一个 TIMESTAMP
列,指示上次更改密码的时间。对于使用 MySQL 内置身份验证插件(mysql_native_password、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
表明帐户是否被锁定(请参阅Account Locking)。
Password_reuse_history
是帐户的Password history
选项的值,默认历史为NULL。
Password_reuse_time
是帐户的 PASSWORD REUSE INTERVAL
选项的值,默认间隔为 NULL。
Password_require_current
(MySQL 8.0.13新增)对应账户的PASSWORD REQUIRE
选项的值,如下表所示。
Password_require_current Value | Corresponding PASSWORD REQUIRE Option |
---|---|
'Y' | PASSWORD REQUIRE CURRENT |
'N' | PASSWORD REQUIRE CURRENT OPTIONAL |
NULL | PASSWORD REQUIRE CURRENT DEFAULT |
User_attributes
(在 MySQL 8.0.14 中添加)是一个 JSON
格式的列,用于存储未存储在其他列中的帐户属性:
additional_password
:二级密码,如果有的话。请参阅 Dual Password Support。- Restrictions:限制列表。限制是通过部分撤销操作添加的。属性值是一个元素数组,每个元素都有
Database
和Restrictions
键,指示受限制数据库的名称及其适用的限制。请参阅 Privilege Restriction Using Partial Revokes Password_locking
:登录失败跟踪和临时帐户锁定的条件。Password_locking
属性根据CREATE USER
和ALTER USER语句的FAILED_LOGIN_ATTEMPTS
和PASSWORD_LOCK_TIME
选项进行更新。failed_login_attempts
和password_lock_time_days
键属性值是一个散列。如果缺少键,则其值隐式为0
。如果键值隐式或显式为0
,则禁用相应的功能。这个属性是在MySQL 8.0.19中添加的。
示例:有二级密码和部分被撤销的数据库权限的帐户在列值中有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' <> '';
table_priv 和 columns_priv 授权表
在访问控制的第二阶段,服务器执行请求验证以确保每个客户端对其发出的每个请求都有足够的权限。除了user
和db
授权表之外,服务器还可以查询tables_priv
和columns_priv
表,以获取涉及到表的请求。后两个表在表和列级别提供更精细的权限控制。他们有如下表所示的列。
Table 6.6 tables_priv and columns_priv Table Columns
Table Name | tables_priv | columns_priv |
---|---|---|
Scope columns | Host | Host |
Db | Db | |
User | User | |
Table_name | Table_name | |
Column_name | ||
Privilege columns | Table_priv | Column_priv |
Column_priv | ||
Other columns | Timestamp | Timestamp |
Grantor |
Timestamp
和 Grantor
列分别设置为当前时间戳和 CURRENT_USER
值,但在其他方面未使用。
procs_priv 授权表
对于涉及存储例程的请求的验证,服务器可以查阅 procs_priv
表,该表具有下表所示的列。
Table Name | procs_priv |
---|---|
Scope columns | Host |
Db | |
User | |
Routine_name | |
Routine_type | |
Privilege columns | Proc_priv |
Other columns | Timestamp |
Grantor |
Routine_type
列是一个 ENUM
列,其值为 'FUNCTION'
或 'PROCEDURE
’ 以表明该行引用的例程类型。此列允许为具有相同名称的函数和过程分别授予特权。
Timestamp
和 Grantor
列未使用。
proxies_priv 授权表
proxies_priv
表记录有关代理帐户的信息。它有这些列:
Host、User
:代理账号;即具有帐代理权限的帐户。Proxied_host、Proxied_user
:代理账户。Grantor,Timestamp
:未使用。with_grant
:代理账户是否可以将代理权限授予其他账户。
global_grants 授权表
global_grants
表列出了当前分配给用户帐户的动态全局权限。该表具有以下列:
-
USER、HOST
:授予权限的帐户的用户名和主机名。 -
PRIV
:权限名称。 -
WITH_GRANT_OPTION
:该账户是否可以将权限授予其他账户。
default_roles 授权表
default_roles
表列出了默认用户角色。它有这些列:
-
HOST、USER
:默认角色适用的帐户或角色。 -
DEFAULT_ROLE_HOST、DEFAULT_ROLE_USER
:默认角色。
password_history 授权表
password_history
表包含有关密码更改的信息。它有这些列:
Host
,User
:发生密码更改的帐户。Password_timestamp
:发生密码更改的时间。Password
:新的密码哈希值。
password_history
表会为每个帐户积累足够数量的非空密码,以使MySQL能够对帐户密码历史长度和重用间隔进行检查。当尝试更改密码时,会自动删除这两个限制之外的条目。
如果一个帐户被重命名,它的条目将被重命名。如果帐户被删除或其身份验证插件被更改,则其条目将被删除。
授权表范围列属性
授权表中的范围列包含字符串。每个列的默认值是空字符串。下表显示了每列中允许的字符数。
Column Name | Maximum Permitted Characters |
---|---|
Host , Proxied_host | 255 (60 prior to MySQL 8.0.17) |
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
列。这些列中的值可以控制的任何权限组合。只会启用列值中列出的那些权限。
Table Name | Column Name | Possible Set Elements |
---|---|---|
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 8.0.22开始,为了允许在MySQL 授权表上并发DML
和DDL
操作,之前在MySQL 授权表上获得行锁的读操作被执行为非锁读。在MySQL授权表上执行的非锁定读操作包括:
SELECT
语句和其他只读语句通过联接列表和子查询从授权表中读取数据。包括SELECT ... FOR SHARE
语句,使用任何事务隔离级别。- 使用任何事务隔离级别从授权表读取数据(通过连接列表或子查询)但不修改它们的
DML
操作。
使用 -binlog_format=mixed
时,从授权表读取数据的 DML
操作将作为行事件写入二进制日志,以使混合模式复制的操作安全。