备注:测试数据库版本为MySQL 8.0
这个blog我们来聊聊MySQL用户及权限
MySQL权限系统通过下面两个阶段进行认证:
1.对连接的用户进行身份认证,合法的用户通过验证,不合法的用户拒绝连接
查看mysql.user表的Host、User、
备注:MySQL 进行身份认证的时候,IP地址和用户名联合进行确认,所以root@localhost 和root@ip 会被MySQL视为不同的用户。
2.对通过认证的合法用户赋予相应的权限,用户可以在这些权限范围内对数据库做相应的操作。
权限相关表:
user(全局级别权限)
db(数据库级别权限)
tables_priv(表级别权限)
columns_priv(列级别的权限)
procs_priv (存储过程和函数的权限)
按照user,db,tables_priv,columns_priv的顺序进行验证。
即先检查全局权限表user,如果user中对应的权限为Y,则此用户对所有数据库的权限都为Y,将不再检查db, tables_priv,columns_priv;
如果为N,则到db表中检查此用户对应的具体数据库,并得到db中为Y的权限;如果db中为N,则检查tables_priv中此数据库对应的具体表,取得表中的权限Y,以此类推。
权限名 | 对应授权表的列 | 用途 |
---|---|---|
All/All Privileges | all privileges | 权限代表全局或者全数据库对象级别的所有权限 |
Alter | Alter_priv | 允许许修改表结构的权限,但必须要求有create和insert权限配合。如果是rename表名,则要求有alter和drop原表, create和insert新表的权限 |
Alter routine | Alter_routine_priv | 允许修改或者删除存储过程、函数的权限 |
Create | Create_priv | 允许创建新的数据库和表的权限 |
Create ROLE | Create_role_priv | 允许创建角色 |
Create routine | Create_routine_priv | 允许创建存储过程、函数的权限 |
Create tablespace | Create_tablespace_priv | 允许创建、修改、删除表空间和日志组的权限 |
Create temporary tables | Create_tmp_table_priv | 允许创建临时表的权限 |
Create user | Create_user_priv | 允许创建、修改、删除、重命名user的权限 |
Create view | Create_view_priv | 允许创建视图的权限 |
Delete | Delete_priv | 允许删除行数据的权限 |
Drop | Drop_priv | 允许删除数据库、表、视图的权限,包括truncate table命令 |
Drop role | Drop_role_priv | 允许删除角色 |
Event | Event_priv | 允许查询,创建,修改,删除MySQL事件 |
Execute | Execute_priv | 代表允许执行存储过程和函数的权限 |
File | File_priv | 允许在MySQL可以访问的目录进行读写磁盘文件操作,可使用的命令包括load data infile,select … into outfile,load file()函数 |
Grant option | Grant_priv | 允许此用户授权或者收回给其他用户你给予的权限,重新付给管理员的时候需要加上这个权限 |
Index | Index_priv | 允许创建和删除索引 |
Insert | Insert_priv | 是否允许在表里插入数据,同时在执行analyze table,optimize table,repair table语句的时候也需要insert权限 |
Lock TABLES | Lock_tables_priv | 允许对拥有select权限的表进行锁定,以防止其他链接对此表的读或写 |
Process | Process_priv | 允许查看MySQL中的进程信息,比如执行show processlist, mysqladmin processlist, show engine等命令 |
PROXY | See proxies_priv table | 想让某个用户具有给他人赋予权限的能力,那么就需要proxy权限了,远程用户也可以 |
Reference | References_priv | 允许创建外键 |
Reload | Reload_priv | 允许执行flush命令 |
Replication client | Repl_client_priv | 允许执行show master status,show slave status,show binary logs命令 |
Replication slave | Repl_slave_priv | 允许slave主机通过此用户连接master以便建立主从复制关系 |
Select | Select_priv | 允许从表中查看数据,update、delete语句有where条件的也需要select权限 |
Show databases | Show_db_priv | 通过执行show databases命令查看所有的数据库名 |
Show view | Show_view_priv | 过执行show create view命令查看视图创建的语句 |
Shutdown | Shutdown_priv | 允许关闭数据库实例,执行语句包括mysqladmin shutdown |
Super | Super_priv | 允许执行一系列数据库管理命令 |
Trigger | Trigger_priv | 允许创建,删除,执行,显示触发器的权限 |
Update | Update_priv | 允许修改表中的数据的权限 |
Usage | “no privileges”的同义词 | 创建一个用户之后的默认权限,其本身代表连接登录权限 |
表名 | user | db |
---|---|---|
范围列 | Host | Host |
User | User | |
DB | ||
权限相关列 | 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字段存放用户认证信息
Password_expired设置成’Y’则表明允许DBA将此用户的密码设置成过期而且过期后要求用户的使用者重置密码(alter user/set password重置密码)
Password_last_changed作为一个时间戳字段代表密码上次修改时间,执行create user/alter user/set password/grant等命令创建用户或修改用户密码时此数值自动更新
Password_lifetime代表从password_last_changed时间开始此密码过期的天数
Account_locked代表此用户被锁住,无法使用
表名 | 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 |
Tables_priv和columns_priv权限值
表名 | 列名 | 对应权限 |
---|---|---|
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’ |
类别 | 列 |
---|---|
范围列 | Host |
Db | |
User | |
Routine_name | |
Routine_type | |
权限列 | Proc_priv |
其它列 | Timestamp |
Grantor |
-- 查看mysql有哪些用户
select user,host from mysql.user;
-- 查看已经授权给用户的权限信息
show grants for root@'%';
执行记录:
mysql> -- 查看mysql有哪些用户
mysql> select user,host from mysql.user;
+------------------+------+
| user | host |
+------------------+------+
| mysql.infoschema | % |
| mysql.session | % |
| mysql.sys | % |
| root | % |
+------------------+------+
mysql> show grants for root@'%'\G
*************************** 1. row ***************************
Grants for root@%: GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE
TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGE
R, CREATE TABLESPACE, CREATE ROLE, DROP ROLE ON *.* TO `root`@`%` WITH GRANT OPTION
1 row in set (0.00 sec)
MySQL的授权用户由两部分组成: 用户名和登录主机名
表达用户的语法为’user_name’@’host_name’
单引号不是必须,但如果其中包含特殊字符则是必须的
”@‘localhost’代表匿名登录的用户
Host_name可以使主机名或者ipv4/ipv6的地址。 Localhost代表本机, 127.0.0.1代表ipv4本机地址, ::1代表ipv6的本机地址
Host_name字段允许使用%和_两个匹配字符,比如’%’代表所有主机, ’%.mysql.com’代表 来自mysql.com这个域名下的所有主机, ‘192.168.1.%’代表所有来自192.168.1网段的主机
User值 | Host 值 | 允许的连接 |
---|---|---|
‘my_user’ | ‘www.mysql.com’ | my_user从www.mysql.com主机连接 |
‘’ | ‘h1.example.net’ | 任何用户从www.mysql.com主机连接 |
‘my_user’ | ‘%’ | my_user从任何主机连接 |
‘’ | ‘%’ | 任何用户,从任何主机连接 |
‘my_user’ | ‘%.mysql.com’ | my_user从mysql.com域中的任何主机连接 |
‘my_user’ | ‘www.mysql.%’ | my_user从连接 www.mysql.com,www.mysql.net,www.mysql.pub,等; 这可能没用 |
‘my_user’ | ‘10.31.1.115’ | my_user从10.31.1.115连接 |
‘my_user’ | ‘10.31.1.%’ | my_user从10.31.1 C类子网中的任何主机连接 |
‘my_user’ | ‘10.31.1.0/255.255.255.0’ | 同上 |
执行Grant,revoke,set password,rename user命令修改权限之后, MySQL会自动将修改后的权限信息同步加载到系统内存中
如果执行insert/update/delete操作上述的系统权限表之后,则必须再执行刷新权限命令才能同步到系统内存中,刷新权限命令包括: flush privileges/mysqladmin flush-privileges / mysqladmin reload
如果是修改tables和columns级别的权限,则客户端的下次操作新权限就会生效
如果是修改database级别的权限,则新权限在客户端执行use database命令后生效
如果是修改global级别的权限,则需要重新创建连接新权限才能生效
如果是修改global级别的权限,则需要重新创建连接新权限才能生效 (例如修改密码)
有两种方式创建MySQL授权用户:
1.执行create user/grant命令(推荐方式)
2.通过insert语句直接操作MySQL系统权限表
创建用户及授权脚本
# 创建my_user1,授予管理员权限
CREATE USER 'my_user1'@'localhost' IDENTIFIED BY 'admin';
GRANT ALL PRIVILEGES ON *.* TO 'my_user1'@'localhost' WITH GRANT OPTION;
# 创建my_user2 用户并赋予常用权限 ,在所有的库和表上
# MySQL 8.0之前可以通过grant语句创建用户,MySQL 8.0之后不允许了
GRANT Create,Insert,Update,Delete,Select,Index *.* TO 'my_user2'@'localhost' IDENTIFIED BY '123456';
CREATE USER 'my_user2'@'localhost' IDENTIFIED BY '123456';
GRANT Create,Insert,Update,Delete,Select,Index ON *.* TO 'my_user2'@'localhost';
# 创建my_user3用户,在test1库,t1表, 上的name1列只有select 权限
CREATE USER 'my_user3'@'localhost' IDENTIFIED BY '123456';
grant select(name1) on test1.t1 to 'my_user3'@'localhost';
执行记录:
mysql> select user,host from mysql.user;
+------------------+------+
| user | host |
+------------------+------+
| mysql.infoschema | % |
| mysql.session | % |
| mysql.sys | % |
| root | % |
+------------------+------+
4 rows in set (0.00 sec)
mysql> # 创建my_user1,然后另开一个授权语句
mysql> CREATE USER 'my_user1'@'localhost' IDENTIFIED BY 'admin';
Query OK, 0 rows affected (0.03 sec)
mysql> GRANT ALL PRIVILEGES ON *.* TO 'my_user1'@'localhost' WITH GRANT OPTION;
Query OK, 0 rows affected (0.01 sec)
# 创建my_user2 用户并赋予常用权限 ,在所有的库和表上
mysql> CREATE USER 'my_user2'@'localhost' IDENTIFIED BY '123456';
Query OK, 0 rows affected (0.01 sec)
mysql> GRANT Create,Insert,Update,Delete,Select,Index ON *.* TO 'my_user2'@'localhost';
Query OK, 0 rows affected (0.01 sec)
mysql>
mysql>
mysql>
mysql> # 创建my_user3用户,在test1库,t1表, 上的name1列只有select 权限
mysql> CREATE USER 'my_user3'@'localhost' IDENTIFIED BY '123456';
Query OK, 0 rows affected (0.01 sec)
mysql> grant select(name1) on test1.t1 to 'my_user3'@'localhost';
Query OK, 0 rows affected (0.01 sec)
mysql>
mysql> select user,host from mysql.user;
+------------------+-----------+
| user | host |
+------------------+-----------+
| mysql.infoschema | % |
| mysql.session | % |
| mysql.sys | % |
| root | % |
| my_user1 | localhost |
| my_user2 | localhost |
| my_user3 | localhost |
+------------------+-----------+
7 rows in set (0.00 sec)
权限表数据
mysql> select * from mysql.user where user = 'my_user1'\G
*************************** 1. row ***************************
Host: localhost
User: my_user1
Select_priv: Y
Insert_priv: Y
Update_priv: Y
Delete_priv: Y
Create_priv: Y
Drop_priv: Y
Reload_priv: Y
Shutdown_priv: Y
Process_priv: Y
File_priv: Y
Grant_priv: Y
References_priv: Y
Index_priv: Y
Alter_priv: Y
Show_db_priv: Y
Super_priv: Y
Create_tmp_table_priv: Y
Lock_tables_priv: Y
Execute_priv: Y
Repl_slave_priv: Y
Repl_client_priv: Y
Create_view_priv: Y
Show_view_priv: Y
Create_routine_priv: Y
Alter_routine_priv: Y
Create_user_priv: Y
Event_priv: Y
Trigger_priv: Y
Create_tablespace_priv: Y
ssl_type:
ssl_cipher: 0x
x509_issuer: 0x
x509_subject: 0x
max_questions: 0
max_updates: 0
max_connections: 0
max_user_connections: 0
plugin: caching_sha2_password
authentication_string: $A$005$`:^,98&aKZ|<v">9vtB9sKI/vTT3bpN0Zn.W7F94.FoVvk/nzSB1dkrsb0
password_expired: N
password_last_changed: 2020-06-17 18:07:05
password_lifetime: NULL
account_locked: N
Create_role_priv: Y
Drop_role_priv: Y
Password_reuse_history: NULL
Password_reuse_time: NULL
Password_require_current: NULL
User_attributes: NULL
1 row in set (0.00 sec)
mysql>
mysql> select * from mysql.user where user = 'my_user2'\G
*************************** 1. row ***************************
Host: localhost
User: my_user2
Select_priv: Y
Insert_priv: Y
Update_priv: Y
Delete_priv: Y
Create_priv: Y
Drop_priv: N
Reload_priv: N
Shutdown_priv: N
Process_priv: N
File_priv: N
Grant_priv: N
References_priv: N
Index_priv: Y
Alter_priv: N
Show_db_priv: N
Super_priv: N
Create_tmp_table_priv: N
Lock_tables_priv: N
Execute_priv: N
Repl_slave_priv: N
Repl_client_priv: N
Create_view_priv: N
Show_view_priv: N
Create_routine_priv: N
Alter_routine_priv: N
Create_user_priv: N
Event_priv: N
Trigger_priv: N
Create_tablespace_priv: N
ssl_type:
ssl_cipher: 0x
x509_issuer: 0x
x509_subject: 0x
max_questions: 0
max_updates: 0
max_connections: 0
max_user_connections: 0
plugin: caching_sha2_password
authentication_string: $A$005$iW4p]eutb^=HR!"}=rwrGeXa26KbtLykSHJ7YOAZtxhGc/fH8nIMvzahEi3A
password_expired: N
password_last_changed: 2020-06-17 18:28:12
password_lifetime: NULL
account_locked: N
Create_role_priv: N
Drop_role_priv: N
Password_reuse_history: NULL
Password_reuse_time: NULL
Password_require_current: NULL
User_attributes: NULL
1 row in set (0.00 sec)
mysql> select * from mysql.user where user = 'my_user3'\G
*************************** 1. row ***************************
Host: localhost
User: my_user3
Select_priv: N
Insert_priv: N
Update_priv: N
Delete_priv: N
Create_priv: N
Drop_priv: N
Reload_priv: N
Shutdown_priv: N
Process_priv: N
File_priv: N
Grant_priv: N
References_priv: N
Index_priv: N
Alter_priv: N
Show_db_priv: N
Super_priv: N
Create_tmp_table_priv: N
Lock_tables_priv: N
Execute_priv: N
Repl_slave_priv: N
Repl_client_priv: N
Create_view_priv: N
Show_view_priv: N
Create_routine_priv: N
Alter_routine_priv: N
Create_user_priv: N
Event_priv: N
Trigger_priv: N
Create_tablespace_priv: N
ssl_type:
ssl_cipher: 0x
x509_issuer: 0x
x509_subject: 0x
max_questions: 0
max_updates: 0
max_connections: 0
max_user_connections: 0
plugin: caching_sha2_password
authentication_string: $A$005$>HP
>HE@y\Z[])WrYu/lB3SQHa.zoFROwzS4OcGotmdCCyttkxWrAhpW4
password_expired: N
password_last_changed: 2020-06-17 18:32:39
password_lifetime: NULL
account_locked: N
Create_role_priv: N
Drop_role_priv: N
Password_reuse_history: NULL
Password_reuse_time: NULL
Password_require_current: NULL
User_attributes: NULL
1 row in set (0.00 sec)
-- DB表都是空数据
mysql> select * from mysql.db where user = 'my_user1'\G
Empty set (0.00 sec)
mysql> select * from mysql.db where user = 'my_user2'\G
Empty set (0.00 sec)
mysql> select * from mysql.db where user = 'my_user3'\G
Empty set (0.00 sec)
-- tables_priv和columns_priv 表只有第三个表有数据
mysql> select * from mysql.tables_priv where user = 'my_user1'\G
Empty set (0.00 sec)
mysql> select * from mysql.tables_priv where user = 'my_user2'\G
Empty set (0.00 sec)
mysql> select * from mysql.tables_priv where user = 'my_user3'\G
*************************** 1. row ***************************
Host: localhost
Db: test1
User: my_user3
Table_name: t1
Grantor: root@localhost
Timestamp: 0000-00-00 00:00:00
Table_priv:
Column_priv: Select
1 row in set (0.00 sec)
mysql>
mysql>
mysql>
mysql>
mysql> select * from mysql.columns_priv where user = 'my_user1'\G
Empty set (0.00 sec)
mysql> select * from mysql.columns_priv where user = 'my_user2'\G
Empty set (0.00 sec)
mysql> select * from mysql.columns_priv where user = 'my_user3'\G
*************************** 1. row ***************************
Host: localhost
Db: test1
User: my_user3
Table_name: t1
Column_name: name1
Timestamp: 0000-00-00 00:00:00
Column_priv: Select
1 row in set (0.00 sec)
通过revoke命令收回用户权限,回收的时候看一下这个用户有哪些权限然后回收
-- 查看用户有哪些权限
show grants for my_user2@'localhost';
-- 回收权限
revoke SELECT, INSERT, UPDATE, DELETE, CREATE, INDEX ON *.* FROM my_user2@'localhost';
-- 再次查看用户权限
show grants for my_user2@'localhost';
执行记录:
mysql> -- 查看用户有哪些权限
mysql> show grants for my_user2@'localhost';
+--------------------------------------------------------------------------------------+
| Grants for my_user2@localhost |
+--------------------------------------------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, INDEX ON *.* TO `my_user2`@`localhost` |
+--------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> -- 回收权限
mysql> revoke SELECT, INSERT, UPDATE, DELETE, CREATE, INDEX ON *.* FROM my_user2@'localhost';
Query OK, 0 rows affected (0.01 sec)
mysql> -- 再次查看用户权限
mysql> show grants for my_user2@'localhost';
+----------------------------------------------+
| Grants for my_user2@localhost |
+----------------------------------------------+
| GRANT USAGE ON *.* TO `my_user2`@`localhost` |
+----------------------------------------------+
1 row in set (0.00 sec)
通过执行drop user命令删除MySQL用户
还可以通过系统权限表删除(不建议)
mysql> drop user my_user2@'localhost';
Query OK, 0 rows affected (0.01 sec)
通过设置全局变量max_user_connections可以限制所有用户在同一时间连接MySQL实例的数量,但此参数无法对每个用户区别对待,所以MySQL提供了对每个用户的资源限制管理
MAX_QUERIES_PER_HOUR:一个用户在一个小时内可以执行查询的次数(基本包含所有语句)
MAX_UPDATES_PER_HOUR:一个用户在一个小时内可以执行修改的次数(仅包含修改数据库或表的语句)
MAX_CONNECTIONS_PER_HOUR:一个用户在一个小时内可以连接MySQL的时间
MAX_USER_CONNECTIONS:一个用户可以在同一时间连接MySQL实例的数量
从5.0.3版本开始,对用户‘user’@‘%.example.com’的资源限制是指所有通过example.com域名主机连接user用户的连接,而不是分别指从host1.example.com和host2.example.com主机过来的连接
-- 设置my_user3 每小时查询500次,每小时修改 100次
ALTER USER 'my_user3'@'localhost' WITH MAX_QUERIES_PER_HOUR 500 MAX_UPDATES_PER_HOUR 100 ;
-- 设置my_user3 一个小时内可以连接MySQL的时间,一个用户可以在同一时间连接MySQL实例的数量
ALTER USER 'my_user3'@'localhost' REQUIRE SSL WITH MAX_CONNECTIONS_PER_HOUR 20 MAX_USER_CONNECTIONS 2;
ALTER USER 'my_user3'@'localhost' IDENTIFIED BY 'mypass';
mysqladmin -u my_user1 -h localhost password "123456"
设置系统参数default_password_lifetime作用于所有的用户账户
default_password_lifetime=180 设置180天过期
default_password_lifetime=0 设置密码不过期
如果为每个用户设置了密码过期策略,则会覆盖上述系统参数
-- 密码90天过去
ALTER USER 'my_user3'@'localhost' PASSWORD EXPIRE INTERVAL 90 DAY;
-- 密码不过期
ALTER USER 'my_user3'@'localhost' PASSWORD EXPIRE NEVER;
-- 默认过期策略
ALTER USER 'my_user3'@'localhost' PASSWORD EXPIRE DEFAULT;
执行记录:
mysql> -- 密码90天过去
mysql> ALTER USER 'my_user3'@'localhost' PASSWORD EXPIRE INTERVAL 90 DAY;
Query OK, 0 rows affected (0.01 sec)
mysql> -- 密码不过期
mysql> ALTER USER 'my_user3'@'localhost' PASSWORD EXPIRE NEVER;
Query OK, 0 rows affected (0.00 sec)
mysql> -- 默认过期策略
mysql> ALTER USER 'my_user3'@'localhost' PASSWORD EXPIRE DEFAULT;
Query OK, 0 rows affected (0.01 sec)
mysql> show variables like 'default_password_lifetime'\G
*************************** 1. row ***************************
Variable_name: default_password_lifetime
Value: 0
1 row in set, 1 warning (0.00 sec)
通过执行create user/alter user命令中带account lock/unlock子句设置用户的lock状态
Create user语句默认的用户是unlock状态
# 修改用户为lock
alter user my_user3@'localhost' account lock;
# 修改用户为unlock
alter user my_user3@'localhost' account unlock;
mysql> # 修改用户为lock
mysql> alter user my_user3@'localhost' account lock;
Query OK, 0 rows affected (0.01 sec)
mysql> # 修改用户为unlock
mysql> alter user my_user3@'localhost' account unlock;
Query OK, 0 rows affected (0.01 sec)
1.https://www.cnblogs.com/keme/p/10288168.html#
2.https://dev.mysql.com/doc/refman/8.0/en/grant-tables.html