前言
MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件之一。本文章收录在MySQL性能优化+原理+实战专栏,由于没有更新完成,暂未收录到开篇介绍中。点击此处查看开篇介绍。

 在学习这一章节的时候,我们可以先了解一下SQL语言,SQL语言共分为四大类:
- 数据查询语言DQL:select 等
- 数据操纵语言DML:insert update delete 等
- 数据定义语言DDL: create drop alter runcate 等
- 数据控制语言DCL: grant revoke commit rollback 等
本文会频繁使用到DC 数据控制语言
点击此处可以了解关系数据库标准语言SQL的概念和发展历史
目录
- 一、访问控制
- 1.1 连接验证(阶段1)
- 1.2 允许的连接
- 1.3 连接的优先级
- 1.4 请求验证(阶段二)
 
- 二、用户管理
- 2.1 新增用户
- 2.2 用户修改
- 2.2.1 使用DDL语言修改用户
- 2.2.2 DML语句管理mysql用户
 
- 2.3 删除用户
- 2.4 查看用户
- 2.4.1 show create user 显示用户非权限属性
- 2.4.2 select * from mysql.user 查看已经创建的用户
- 2.4.3 select current_user() 查看当前登录用户
 
 
- 三、密码管理
- 3.1 修改密码
- 3.1.1 基本使用 alter
- 3.1.2 其他方式 mysqladmin
- 3.1.3 其他方式 set password
- 3.1.4 修改当前登录用户密码
 
- 3.2 密码策略
- 3.2.1 密码立即过期策略 PASSWORD EXPIRE
- 3.2.2 密码从不过期策略 EXPIRE NEVER
- 3.2.3 默认过期时间策略 PASSWORD EXPIRE DEFAULT
- 3.2.4 指定过期时间策略 EXPIRE INTERVAL 90 DAY
 
- 3.3 set password
- 3.4 密码过期策略
- 3.4.1 全局参数
- 3.4.2 指定账户设置
- 3.4.3 处理密码过期
 
- 3.5 密码插件
- 3.5.1 mysql 5.7 版本默认使用的密码插件
- 3.5.2 mysql 8.0 版本默认使用的密码插件
- 3.5.3 mysql 8 要兼容之前版本
 
 
- 四、用户权限管理
- 4.1 权限粒度
- 4.2 显示用户非权限属性
- 4.3 全局级权限
- 4.4 库级别权限
- 4.5 表级权限
- 4.6 列级权限
- 4.7 权限回收
- 4.7.1 回收部分权限
- 4.7.2 回收全部权限
 
- 4.8 mysql权限汇总
 
- 五、资源限制
- 5.1 用户创建指定配额
- 5.2 修改配额
 
- 六、案例
- 6.1 断开已删除用户
 
- 七、MySQL 8.0 关于用户和权限新特征
一、访问控制
1.1 连接验证(阶段1)
当我们连接MySQL的时候,MySQL会以下面2点进行连接验证
- 通过提供的账号和密码来验证身份
- 验证账号是否锁定
服务首先检查凭据,然后检查账户的锁定状态。任一步骤失败都会拒绝访问,没有问题就接收连接。锁定状态记录在user表account_locked列中。
mysql> select user,account_locked from user;
+--------+----------------+
| user   | account_locked |
+--------+----------------+
| root   | N              |
| multis | N              |
| multis | N              |
| root   | N              |
+--------+----------------+
4 rows in set (0.00 sec)
1.2 允许的连接
下表展示了User和Host值在各种的组合下, user表适用于传入的连接
| 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.net%’ | 从x.example.net,从x.example.com等的任何主机的fred | 
| ‘fred’ | ‘198.51.100.177’ | 从ip198.51.100.177主机的fred | 
| ‘fred’ | ‘198.51.100.%’ | 从ip198.51.100C类网中任何主机的fred | 
| ‘fred’ | '198.51.100.0/255.255.255.0 | 与前面相同 | 
1.3 连接的优先级
当有多个匹配项时,需要确认使用哪个匹配项,按照以下的方式解决问题
- 当服务器将user表读入内存,它会对user表进行排序
- 客户端尝试连接时,服务器将按排序顺序浏览各行
- 服务器使用与客户端主机名和用户名匹配的第一行
排序顺序
- 优先Host进行排序,其次User
- 有具体文字比%更具有高优先级(127.0.0.1比localhost高)
示例一
 要查看其工作原理,假设user 表如下所示:
+-----------+----------+-
| Host      | User     | ...
+-----------+----------+-
| %         | root     | ...
| %         | jeffrey  | ...
| localhost | root     | ...
| localhost |          | ...
+-----------+----------+-
读入到内存时,自动排序后的结果如下所示:
+-----------+----------+-
| Host      | User     | ...
+-----------+----------+-
| localhost | root     | ...
| localhost |          | ...
| %         | jeffrey  | ...
| %         | root     | ...
+-----------+----------+-
挡localhost 上的root用户连接mysql时候,这个时候会匹配| localhost | root |这个条目对应的权限。 其他条目虽然也满足, 但不会匹配它们对应的权限。
示例二
我们创建'test'@'%'和''@'192.168.79.140’两个用户,进行连接的优先级的测试
[root@mysql2 ~]# mysql -root-p123456
## 忽略部分登陆代码 ##
mysql> create user ''@'192.168.79.140' identified by '123456';
mysql> create user 'test'@'%' identified by '123456';
mysql> select host,user from user;
+----------------+------+
| host           | user |
+----------------+------+
| %              | test |
| 192.168.79.140 |      |
| localhost      | root |
+----------------+------+
3 rows in set (0.00 sec)
mysql> exit;
使用我们刚才创建的'test'@'%'用户登录mysql
[root@mysql2 ~]# mysql -utest -p123456 -h192.168.79.140
按照mysql连接的优先级,用户在登陆mysql时,mysql读入到内存自动排序后的结果应如下所示:
+----------------+------+
| host           | user |
+----------------+------+
| 192.168.79.140 |      |
| localhost      | root |
| %              | test |
+----------------+------+
当前登录的'test'@'%'用户匹配连接是| 192.168.79.140 | |,我们可以通过CURRENT_USER()函数查验证当前用户是否匹配| 192.168.79.140 | |
mysql> select current_user();
+-----------------+
| current_user()  |
+-----------------+
| @192.168.79.140 |
+-----------------+
1 row in set (0.00 sec)
验证结果如我们推测一致,正式坏境中建议不要创建有不带用户名只有主机的用户。
1.4 请求验证(阶段二)
MySQL建立连接后,服务器进入访问控制的第二阶段。该连接发出的每个请求,会检查是否具有足够的权限,这些权限对应着如下这些表:
- user用户(全局)
- db数据库
- tables_priv表
- columns_priv列
- procs_priv存储过程
- proxies_priv代理用户权限
二、用户管理
在这里我们需要知道的是mysql的用户名和主机名在一起才是一个有效的用户
2.1 新增用户
MySQL的语法和Oracle是相似的,如下
 create user 'user'@'localhost' identified by 'passwd' [ACCOUNT UNLOCK]
ACCOUNT UNLOCK 用户默认是没有锁定的,如果用户锁定,我们登录的用户不会有第二阶段的请求验证。
我们创建一个本地可以登陆的multis用户,该用户默认是未锁定的状态。
mysql> create user 'multis'@'localhost' identified by '123456';
Query OK, 0 rows affected (0.00 sec)
2.2 用户修改
MySQL是可以通过数据操纵语言DML和数据定义语言DDL来进行修改的
2.2.1 使用DDL语言修改用户
我们查询当前数据库所有的用户名、主机和用户的状态
mysql> select user,host,account_locked from user;
+--------+-----------+----------------+
| user   | host      | account_locked |
+--------+-----------+----------------+
| root   | localhost | N              |
| multis | localhost | N              |
+--------+-----------+----------------+
2 rows in set (0.00 sec)
1、我们使用alter修改'multis'@'localhost'用户状态为锁定状态
mysql> alter user 'multis'@'localhost' account lock;
Query OK, 0 rows affected (0.00 sec)
mysql> select user,host,account_locked from user;
+--------+-----------+----------------+
| user   | host      | account_locked |
+--------+-----------+----------------+
| root   | localhost | N              |
| multis | localhost | Y              |
+--------+-----------+----------------+
2 rows in set (0.00 sec)
重新打开一个窗口进行mysql登陆,登陆的时候,MySQL报错ERROR 3118 (HY000): Access denied for user 'multis'@'localhost'. Account is locked.帐号被锁定,用户被拒绝访问。
[root@mysql2 ~]# mysql -umultis -p
Enter password: 
ERROR 3118 (HY000): Access denied for user 'multis'@'localhost'. Account is locked.
2、我们使用alter修改'test'@'localhost'用户的密码
mysql> alter user 'test'@'localhost' identified by '654321';
Query OK, 0 rows affected (0.01 sec)
我们登陆'test'@'localhost'用户验证
[root@mysql2 ~]# mysql -utest -p654321
## 省略部分登陆提示 ##
mysql> 
'test'@'localhost'用户使用修改后密码登陆成功
2.2.2 DML语句管理mysql用户
我们也可以直接更新mysql.user表的信息,进行用户的管理,但是需要flush privileges,将内存和磁盘中的数据保持一致。
1、修改'multis' @'localhost'用户用户名为multis1
mysql> update mysql.user set user = 'multis1' where user = 'multis' and host='localhost';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
查询mysql.user表,进行校验
mysql> select user,host from mysql.user;
+---------+-----------+
| user    | host      |
+---------+-----------+
| multis1 | localhost |
| root    | localhost |
+---------+-----------+
2 rows in set (0.00 sec)
2、修改'multis1' @'localhost'用户host为127.0.0.1
mysql> update mysql.user set host = '127.0.0.1' where user = 'multis1' and host='localhost';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
我们不刷新flush privileges,查询'multis1' @'localhost'用户信息
mysql> select user,host from mysql.user;
+---------+-----------+
| user    | host      |
+---------+-----------+
| multis1 | localhost |
| root    | localhost |
+---------+-----------+
2 rows in set (0.00 sec)
发现虽然更改了host,但是还以前的host,我们flush privileges后,继续查询'multis1' @'localhost'用户信息
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
mysql> select user,host from mysql.user;
+---------+-----------+
| user    | host      |
+---------+-----------+
| multis1 | 127.0.0.1 |
| root    | localhost |
+---------+-----------+
2 rows in set (0.00 sec)
2.3 删除用户
方法一:drop user
mysql> create user 'test'@'localhost' identified by '123456' account unlock;
Query OK, 0 rows affected (0.00 sec)
mysql> drop user 'test'@'localhost';
Query OK, 0 rows affected (0.00 sec
方案二:delete
mysql> create user 'test'@'localhost' identified by '123456' account unlock;
Query OK, 0 rows affected (0.00 sec)
mysql> delete from mysql.user where user = 'test' and host='localhost';
Query OK, 1 row affected (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
2.4 查看用户
2.4.1 show create user 显示用户非权限属性
mysql> create user test@'localhost' identified by '123456';
Query OK, 0 rows affected (0.00 sec)
mysql> show create user 'test'@'localhost' \G;
*************************** 1. row ***************************
CREATE USER for test@localhost: CREATE USER 'test'@'localhost' IDENTIFIED WITH 'mysql_native_password' AS '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK
1 row in set (0.00 sec)
ERROR: 
No query specified

2.4.2 select * from mysql.user 查看已经创建的用户
mysql> select * from mysql.user where user='test' and host='localhost' \G;
*************************** 1. row ***************************
                  Host: localhost
                  User: test
           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: 
           x509_issuer: 
          x509_subject: 
         max_questions: 0
           max_updates: 0
       max_connections: 0
  max_user_connections: 0
                plugin: mysql_native_password
 authentication_string: *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9
      password_expired: N
 password_last_changed: 2023-04-18 22:00:36
     password_lifetime: NULL
        account_locked: N
1 row in set (0.00 sec)
ERROR: 
No query specified
2.4.3 select current_user() 查看当前登录用户
mysql> select current_user;
+----------------+
| current_user   |
+----------------+
| root@localhost |
+----------------+
1 row in set (0.00 sec)
mysql> select user();
+----------------+
| user()         |
+----------------+
| root@localhost |
+----------------+
1 row in set (0.00 sec)
三、密码管理
3.1 修改密码
3.1.1 基本使用 alter
mysql> alter user 'test'@'localhost' identified by '654321';
Query OK, 0 rows affected (0.01 sec)
3.1.2 其他方式 mysqladmin
[root@mysql2 ~]# mysqladmin -utest -p654321 password
mysqladmin: [Warning] Using a password on the command line interface can be insecure.
New password: 
Confirm new password: 
Warning: Since password will be sent to server in plain text, use ssl connection to ensure password safety.
3.1.3 其他方式 set password
1 、使用默认加密
mysql> set password for 'test'@'%' ='abcdefg';
Query OK, 0 rows affected (0.01 sec)
2、使用PASSWORD()函数加密(mysql使用该方式进行密码加密)
mysql> set password for 'test'@'%' =password('123456');
Query OK, 0 rows affected (0.01 sec)
3.1.4 修改当前登录用户密码
mysql> alter user current_user() identified by '123456';
Query OK, 0 rows affected (0.00 sec)
mysql> alter user user() identified by '123456';
Query OK, 0 rows affected (0.00 sec)
3.2 密码策略
在设置密码策略时 identified by 'password' 可以忽略
3.2.1 密码立即过期策略 PASSWORD EXPIRE
ERROR 1820 (HY000): You must reset your password using ALTER USER statement before executing this statement.
重置密码后才能正常登陆
修改'test'@'localhost'用户密码立即过期,查询改用户的非权限属性
mysql> alter user 'test'@'localhost' identified by '123456' password expire;
Query OK, 0 rows affected (0.00 sec)
mysql> show create user 'test'@localhost \G;
*************************** 1. row ***************************
CREATE USER for test@localhost: CREATE USER 'test'@'localhost' IDENTIFIED WITH 'mysql_native_password' AS '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' REQUIRE NONE PASSWORD EXPIRE ACCOUNT UNLOCK
1 row in set (0.00 sec)
ERROR: 
No query specified
我们可以发现密码策略从PASSWORD EXPIRE DEFAULT变为PASSWORD EXPIRE,我们重新登陆mysql,发现使用sql语句时无法使用,提示在执行该语句之前,必须使用ALTER USER语句重置密码
mysql> select current_user();
ERROR 1820 (HY000): You must reset your password using ALTER USER statement before executing this statement.
使用root用户修改'test'@'localhost'用户密码
mysql> alter user 'test'@'localhost' identified by '123456';
Query OK, 0 rows affected (0.01 sec)
密码修改完成后,可以正常登陆mysql
[root@mysql2 ~]# mysql -utest -p123456
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
+--------------------+
1 row in set (0.00 sec)
3.2.2 密码从不过期策略 EXPIRE NEVER
查询'test'@'localhost'用户非权限属性
mysql> show create user 'test'@'localhost' \G;
*************************** 1. row ***************************
CREATE USER for test@localhost: CREATE USER 'test'@'localhost' IDENTIFIED WITH 'mysql_native_password' AS '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK
1 row in set (0.00 sec)
ERROR: 
No query specified
修改'test'@'localhost'用户密码永不过期
mysql> alter user 'test'@'localhost' identified by '123456' password expire;
Query OK, 0 rows affected (0.00 sec)
查询'test'@'localhost'用户非权限属性
mysql> show create user 'test'@'localhost' \G;
*************************** 1. row ***************************
CREATE USER for test@localhost: CREATE USER 'test'@'localhost' IDENTIFIED WITH 'mysql_native_password' AS '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' REQUIRE NONE PASSWORD EXPIRE NEVER ACCOUNT UNLOCK
1 row in set (0.00 sec)
ERROR: 
No query specified
当前 'test'@'localhost' 用户永不过期。
3.2.3 默认过期时间策略 PASSWORD EXPIRE DEFAULT
创建用户时,mysql默认的是该策略PASSWORD EXPIRE DEFAULT
查询 'test'@'localhost' 用户非权限属性
mysql> show create user 'test'@'localhost' \G;
*************************** 1. row ***************************
CREATE USER for test@localhost: CREATE USER 'test'@'localhost' IDENTIFIED WITH 'mysql_native_password' AS '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' REQUIRE NONE PASSWORD EXPIRE NEVER ACCOUNT UNLOCK
1 row in set (0.00 sec)
ERROR: 
No query specified
我们可以看出当前 'test'@'localhost' 用于密码策略是永不过期,我们修改为默认设置过期时间策略
mysql> alter user 'test'@'localhost' password expire default;
Query OK, 0 rows affected (0.01 sec)
查询 'test'@'localhost' 用户非权限属性
mysql> show create user 'test'@'localhost' \G;
*************************** 1. row ***************************
CREATE USER for test@localhost: CREATE USER 'test'@'localhost' IDENTIFIED WITH 'mysql_native_password' AS '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK
1 row in set (0.00 sec)
ERROR: 
No query specified
当前 'test'@'localhost' 用户默认时间过期,后面会详解
3.2.4 指定过期时间策略 EXPIRE INTERVAL 90 DAY
查询 'test'@'localhost' 用户非权限属性
mysql> show create user 'test'@'localhost' \G;
*************************** 1. row ***************************
CREATE USER for test@localhost: CREATE USER 'test'@'localhost' IDENTIFIED WITH 'mysql_native_password' AS '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK
1 row in set (0.00 sec)
ERROR: 
No query specified
我们可以看出当前 'test'@'localhost' 密码是默认过期时间策略,我们修改为指定过期间隔策略
mysql> alter user 'test'@'localhost' password expire interval 90 day;
Query OK, 0 rows affected (0.00 sec)
查询 'test'@'localhost' 用户非权限属性
mysql> show create user 'test'@'localhost' \G;
*************************** 1. row ***************************
CREATE USER for test@localhost: CREATE USER 'test'@'localhost' IDENTIFIED WITH 'mysql_native_password' AS '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' REQUIRE NONE PASSWORD EXPIRE INTERVAL 90 DAY ACCOUNT UNLOCK
1 row in set (0.00 sec)
ERROR: 
No query specified
当前 'test'@'localhost' 用户90天以后过期,过期后需要我们修改 'test'@'localhost' 密码。
3.3 set password
使用Sset password修改密码有两种
1 、使用默认加密
mysql> set password for 'test'@'%' ='abcdefg';
Query OK, 0 rows affected (0.01 sec)
2、使用password()函数加密(mysql采用该方式进行密码的加密)
mysql> set password for 'test'@'%' =password('123456');
Query OK, 0 rows affected (0.01 sec)
3.4 密码过期策略
在密码策略中,有4种密码过期策略,其中默认过期策略需要全局参数配置
3.4.1 全局参数
我们可以使用select @@default_password_lifetime来查询密码过期的全局参数,默认值为0
mysql> select @@default_password_lifetime ;
+-----------------------------+
| @@default_password_lifetime |
+-----------------------------+
|                           0 |
+-----------------------------+
1 row in set (0.00 sec)
如果需要修改全局参数,在服务器中my.cnf参数文件中修改或者添加default_password_lifetime参数,重启服务mysql服务生效
[mysqld]
default_password_lifetime=180
default_password_lifetime=180 密码有效期为6个月,最大值65535
default_password_lifetime=0 密码永不过期
停止mysql服务
mysql> shutdown;
Query OK, 0 rows affected (0.01 sec)
mysql> exit
修改参数文件
[root@mysql2 ~]# vim /etc/my.cnf
[root@mysql2 ~]# cat /etc/my.cnf 

 启动mysql服务
[root@mysql2 ~]# nohup mysqld --defaults-file=/etc/my.cnf &
[root@mysql2 ~]# lsof -i:3306
COMMAND  PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
mysqld  1321 mysql   15u  IPv6  24478      0t0  TCP *:mysql (LISTEN)
登陆msyql,查询全局参数
[root@mysql2 ~]# mysql -uroot -p123456
## 忽略mysql登陆部分 ##
mysql> select @@default_password_lifetime;
+-----------------------------+
| @@default_password_lifetime |
+-----------------------------+
|                         180 |
+-----------------------------+
1 row in set (0.00 sec)
3.4.2 指定账户设置
现在要求每90天更改一次密码,我们可以创建用户的时候指定90天后密码过期
mysql> create user 'test1'@'localhost' identified by '123456' password expire interval 90 day;
Query OK, 0 rows affected (0.00 sec)
也可以创建完用户,密码策略为默认时间过期,默认时间就是我们的全局参数,90天
mysql> create user 'test2'@'localhost' identified by '123456';
Query OK, 0 rows affected (0.00 sec)
mysql> show create user 'test2'@'localhost' \G;
*************************** 1. row ***************************
CREATE USER for test2@localhost: CREATE USER 'test2'@'localhost' IDENTIFIED WITH 'mysql_native_password' AS '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK
1 row in set (0.00 sec)
ERROR: 
No query specified
我们修改密码过期策略为指定时间过期
mysql> alter user 'test2'@'localhost' password expire interval 90 day;
Query OK, 0 rows affected (0.00 sec)
mysql> show create user 'test2'@'localhost' \G;
*************************** 1. row ***************************
CREATE USER for test2@localhost: CREATE USER 'test2'@'localhost' IDENTIFIED WITH 'mysql_native_password' AS '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' REQUIRE NONE PASSWORD EXPIRE INTERVAL 90 DAY ACCOUNT UNLOCK
1 row in set (0.00 sec)
ERROR: 
No query specified
我们需要注意的是,当我们指定了用户的是密码立即失效、永久生效和指定过期间隔策略都会覆盖该语句命名的用户的全局策略。当指定用户默认过期时间,用户将会遵循全局密码策略。
3.4.3 处理密码过期
我们创建一个用户,默认策略是全局参数
mysql> create user 'test3'@'localhost' identified by '123456';
Query OK, 0 rows affected (0.00 sec)
mysql> show create user 'test3'@'localhost';
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| CREATE USER for test3@localhost                                                                                                                                            |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| CREATE USER 'test3'@'localhost' IDENTIFIED WITH 'mysql_native_password' AS '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
修改当前用户立即失效
mysql> alter user 'test3'@'localhost' password expire;
Query OK, 0 rows affected (0.00 sec)
mysql> show create user 'test3'@'localhost';
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| CREATE USER for test3@localhost                                                                                                                                    |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| CREATE USER 'test3'@'localhost' IDENTIFIED WITH 'mysql_native_password' AS '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' REQUIRE NONE PASSWORD EXPIRE ACCOUNT UNLOCK |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
打开新的窗口登陆mysql,查询数据
[root@mysql2 ~]# mysql -utest3 -p123456
## 忽略登陆部分 ##
mysql> show databases;
ERROR 1820 (HY000): You must reset your password using ALTER USER statement before executing this statement.
mysql> 
修改密码并查询用户密码过期策略
mysql> alter user 'test3'@'localhost' identified by '123456';
Query OK, 0 rows affected (0.00 sec)
mysql> show create user 'test3'@'localhost' \G;
*************************** 1. row ***************************
CREATE USER for test3@localhost: CREATE USER 'test3'@'localhost' IDENTIFIED WITH 'mysql_native_password' AS '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK
1 row in set (0.00 sec)
ERROR: 
No query specified
重新打开窗口,进行mysql登陆
[root@mysql2 ~]# mysql -utest3 -p123456
## 忽略登陆部分 ##
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
+--------------------+
1 row in set (0.00 sec)
经过上面测试,我们得知修改密码,可以处理密码过期
3.5 密码插件
3.5.1 mysql 5.7 版本默认使用的密码插件
mysql_native_password
mysql> show variables like '%authentication%';
+-------------------------------+-----------------------+
| Variable_name                 | Value                 |
+-------------------------------+-----------------------+
| default_authentication_plugin | mysql_native_password | 
+-------------------------------+-----------------------+
1 row in set (0.78 sec)
3.5.2 mysql 8.0 版本默认使用的密码插件
caching_sha2_password
mysql> select @@default_authentication_plugin ;
+---------------------------------+
| @@default_authentication_plugin |
+---------------------------------+
| caching_sha2_password           |
+---------------------------------+
1 row in set, 1 warning (0.00 sec)
3.5.3 mysql 8 要兼容之前版本
方法一:alter 修改用户指定密码插件
mysql> alter user 'root'@'localhost' identified with mysql_native_password by '123456';
Query OK, 0 rows affected (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.01 sec)
方法二:编辑my.cnf文件,更改默认的身份认证插件
[root@mysql2 ~]#  vim /etc/my.cnf
在[mysqld]中添加如下参数
default_authentication_plugin=mysql_native_password
四、用户权限管理
MySQL数据库对于对象的操作级别分为:全局、数据库、表、字段等。粒度从粗到细。如果粗的粒度的权限满足了,将不再检验细粒度的级别,也就是说全局权限满足了,就不会校验数据库、表和字段,依次类推。
4.1 权限粒度
| 权限相关的表 | 描述 | 
|---|---|
| user | 用户账号,全局权限,连接权限 | 
| db | 数据库级别权限 | 
| tables_priv | 表级别权限 | 
| columns_priv | 列级别权限 | 
| procs_priv | 存储过程,函数级别权限 | 
| proxies_priv | 代理用户权限 | 
4.2 显示用户非权限属性
mysql> show create user 'grant'@'localhost' \G;
*************************** 1. row ***************************
CREATE USER for grant@localhost: CREATE USER 'grant'@'localhost' IDENTIFIED WITH 'mysql_native_password' AS '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK
1 row in set (0.00 sec)
ERROR: 
No query specified
4.3 全局级权限
我们创建‘grant’@'localhost'用户进行权限的学习
mysql> create user 'grant'@'localhost' identified by '123456';
Query OK, 0 rows affected (0.00 sec)
使用show grants for查询用户权限,可以看到刚才创建的用户拥有USAGE权限
mysql> show grants for 'grant'@'localhost' \G;
*************************** 1. row ***************************
Grants for grant@localhost: GRANT USAGE ON *.* TO 'grant'@'localhost'
1 row in set (0.00 sec)
ERROR: 
No query specified
授予用户replication client 和 replication slave用户级权限后进行用户权限的查询
mysql> grant replication client , replication slave on *.* to 'grant'@'localhost';
Query OK, 0 rows affected (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
mysql> show grants for 'grant'@'localhost' \G;
*************************** 1. row ***************************
Grants for grant@localhost: GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'grant'@'localhost'
1 row in set (0.00 sec)
ERROR: 
No query specified
查询用户权限,全局级权限对应的mysql.user表
mysql> select * from mysql.user where user='grant' \G;
*************************** 1. row ***************************
                  Host: localhost
                  User: grant
           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: Y
      Repl_client_priv: Y
      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: 
           x509_issuer: 
          x509_subject: 
         max_questions: 0
           max_updates: 0
       max_connections: 0
  max_user_connections: 0
                plugin: mysql_native_password
 authentication_string: *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9
      password_expired: N
 password_last_changed: 2023-04-20 22:37:57
     password_lifetime: NULL
        account_locked: N
1 row in set (0.00 sec)
ERROR: 
No query specified
4.4 库级别权限
这里创建一个数据库,模拟测试库级别权限,在这里我们回顾一下字符集的设置创建表的时候没有指定字符集,默认使用数据库,如果数据库也没有设置,就默认使用server的字符集。
mysql> show variables like 'character%';
+--------------------------+----------------------------------------------------------------+
| Variable_name            | Value                                                          |
+--------------------------+----------------------------------------------------------------+
| character_set_client     | utf8                                                           |
| character_set_connection | utf8                                                           |
| character_set_database   | utf8                                                           |
| character_set_filesystem | binary                                                         |
| character_set_results    | utf8                                                           |
| character_set_server     | utf8                                                           |
| character_set_system     | utf8                                                           |
| character_sets_dir       | /opt/mysql/mysql-5.7.39-linux-glibc2.12-x86_64/share/charsets/ |
+--------------------------+----------------------------------------------------------------+
8 rows in set (0.00 sec)
创建数据库,默认字符集utf8
mysql> create database testdb default character set utf8;
Query OK, 1 row affected (0.00 sec)
授予‘grant’@'localhost'用户testdb 库级的权限
mysql> grant select,insert,update,delete,create,alter,lock tables,show view,trigger on tesdb.* to 'grant'@'localhost';
Query OK, 0 rows affected (0.01 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
查询用户权限
mysql> show grants for 'grant'@'localhost' \G;
*************************** 1. row ***************************
Grants for grant@localhost: GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'grant'@'localhost'
*************************** 2. row ***************************
Grants for grant@localhost: GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, LOCK TABLES, SHOW VIEW, TRIGGER ON `tesdb`.* TO 'grant'@'localhost'
2 rows in set (0.00 sec)
ERROR: 
No query specified
查询库级别权限,库级别权限对应的表是mysql.db表
mysql> select * from mysql.db where user='grant' \G;
*************************** 1. row ***************************
                 Host: localhost
                   Db: tesdb
                 User: grant
          Select_priv: Y
          Insert_priv: Y
          Update_priv: Y
          Delete_priv: Y
          Create_priv: Y
            Drop_priv: N
           Grant_priv: N
      References_priv: N
           Index_priv: N
           Alter_priv: Y
Create_tmp_table_priv: N
     Lock_tables_priv: Y
     Create_view_priv: N
       Show_view_priv: Y
  Create_routine_priv: N
   Alter_routine_priv: N
         Execute_priv: N
           Event_priv: N
         Trigger_priv: Y
1 row in set (0.00 sec)
ERROR: 
No query specified
4.5 表级权限
我们创建一张表,进行权限的学习
mysql> use testdb;
Database changed
mysql> create table test1 (id int, name varchar(20));
Query OK, 0 rows affected (0.01 sec)
mysql> show tables;
+------------------+
| Tables_in_testdb |
+------------------+
| test1            |
+------------------+
1 row in set (0.00 sec)
授予‘grant’@'localhost'用户testdb.test1 表级别的权限
mysql> grant  select,insert,update,delete,create,alter  on testdb.test1 to 'grant'@'localhost';
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
查询用户权限
mysql> show grants for 'grant'@'localhost' \G;
*************************** 1. row ***************************
Grants for grant@localhost: GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'grant'@'localhost'
*************************** 2. row ***************************
Grants for grant@localhost: GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, LOCK TABLES, SHOW VIEW, TRIGGER ON `tesdb`.* TO 'grant'@'localhost'
*************************** 3. row ***************************
Grants for grant@localhost: GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER ON `testdb`.`test1` TO 'grant'@'localhost'
3 rows in set (0.00 sec)
ERROR: 
No query specified
查询表级别权限,表级别对应的mysql.tables_priv表
mysql> select *  from mysql.tables_priv where table_name='test1'\G;
*************************** 1. row ***************************
       Host: localhost
         Db: testdb
       User: grant
 Table_name: test1
    Grantor: root@localhost
  Timestamp: 0000-00-00 00:00:00
 Table_priv: Select,Insert,Update,Delete,Create,Alter
Column_priv: 
1 row in set (0.00 sec)
ERROR: 
No query specified
4.6 列级权限
我们授予授予‘grant’@'localhost'用户testdb.test1 表id字段查询权限,name字段更新权限
mysql> grant select(id),update(name) on testdb.test1 to 'grant'@'localhost';
Query OK, 0 rows affected (0.04 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
查询用户权限
mysql> show grants for 'grant'@'localhost' \G;
*************************** 1. row ***************************
Grants for grant@localhost: GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'grant'@'localhost'
*************************** 2. row ***************************
Grants for grant@localhost: GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, LOCK TABLES, SHOW VIEW, TRIGGER ON `tesdb`.* TO 'grant'@'localhost'
*************************** 3. row ***************************
Grants for grant@localhost: GRANT SELECT, SELECT (id), INSERT, UPDATE, UPDATE (name), DELETE, CREATE, ALTER ON `testdb`.`test1` TO 'grant'@'localhost'
3 rows in set (0.00 sec)
ERROR: 
No query specified
查询列级别权限
列级别对应的mysql.tables_priv表或者columns_priv表,但是我们查询mysql.tables_priv表发现列级别权限有更查询和更新权限,但不知道是哪一列
mysql> select * from mysql.tables_priv where table_name = 'test1' \G;
*************************** 1. row ***************************
       Host: localhost
         Db: testdb
       User: grant
 Table_name: test1
    Grantor: root@localhost
  Timestamp: 0000-00-00 00:00:00
 Table_priv: Select,Insert,Update,Delete,Create,Alter
Column_priv: Select,Update
1 row in set (0.00 sec)
ERROR: 
No query specified
查询mysql.columns_priv表可以明确看出哪一列有什么权限
mysql> select * from mysql.columns_priv where table_name = 'test1' \G;
*************************** 1. row ***************************
       Host: localhost
         Db: testdb
       User: grant
 Table_name: test1
Column_name: id
  Timestamp: 0000-00-00 00:00:00
Column_priv: Select
*************************** 2. row ***************************
       Host: localhost
         Db: testdb
       User: grant
 Table_name: test1
Column_name: name
  Timestamp: 0000-00-00 00:00:00
Column_priv: Update
2 rows in set (0.00 sec)
ERROR: 
No query specified
4.7 权限回收
查询用户权限
mysql> show grants for 'grant'@'localhost' \G;
*************************** 1. row ***************************
Grants for grant@localhost: GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'grant'@'localhost'
*************************** 2. row ***************************
Grants for grant@localhost: GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, LOCK TABLES, SHOW VIEW, TRIGGER ON `tesdb`.* TO 'grant'@'localhost'
*************************** 3. row ***************************
Grants for grant@localhost: GRANT SELECT, SELECT (id), INSERT, UPDATE, UPDATE (name), DELETE, CREATE, ALTER ON `testdb`.`test1` TO 'grant'@'localhost'
3 rows in set (0.00 sec)
ERROR: 
No query specified
在这里,我们需要知道MySQL权限机制中,在一个数据库上多次赋予权限,权限会自动合并;但在多个库上多次赋予权限,每个库上都会认为是单独的一组权限。若要收回,必须单独对相应的库使用revoke命令。
4.7.1 回收部分权限
使用revoke 进行权限的回收
mysql> revoke select(id), update(name) ON  testdb.test1 from 'grant'@'localhost';
Query OK, 0 rows affected (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
查询用户权限
mysql> show grants for 'grant'@'localhost' \G;
*************************** 1. row ***************************
Grants for grant@localhost: GRANT USAGE ON *.* TO 'grant'@'localhost'
*************************** 2. row ***************************
Grants for grant@localhost: GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, LOCK TABLES, SHOW VIEW, TRIGGER ON `tesdb`.* TO 'grant'@'localhost'
2 rows in set (0.00 sec)
ERROR: 
No query specified
4.7.2 回收全部权限
mysql> revoke all privileges on *.* from 'grant'@'localhost';
Query OK, 0 rows affected (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
查询用户权限
mysql> show grants for 'grant'@'localhost' \G;
*************************** 1. row ***************************
Grants for grant@localhost: GRANT USAGE ON *.* TO 'grant'@'localhost'
*************************** 2. row ***************************
Grants for grant@localhost: GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, LOCK TABLES, SHOW VIEW, TRIGGER ON `tesdb`.* TO 'grant'@'localhost'
2 rows in set (0.00 sec)
ERROR: 
No query specified
回收库级别权限
mysql> revoke select, insert, update, delete, create, alter, lock tables, show view, trigger on tesdb.* from 'grant'@'localhost';
Query OK, 0 rows affected (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
mysql> show grants for 'grant'@'localhost' \G;
*************************** 1. row ***************************
Grants for grant@localhost: GRANT USAGE ON *.* TO 'grant'@'localhost'
1 row in set (0.00 sec)
ERROR: 
No query specified
4.8 mysql权限汇总
mysql一共有29个权限,如下表格
| 权限 | 权限描述 | 
|---|---|
| usage | 连接登陆权限,建立一个用户,就会自动授予其usage权限,该权限只能用于数据库的登陆,不能执行任何操作,且usage权限不能被回收,也即revoke用户并不能删除用户 | 
| file | 拥有file权限才可以执行select…into,outfile和loaddatainfile…操作,一般不给,有严重的安全隐患 | 
| super | 管理员级命令的使用,如change、master、kill、thread、mysqladmin、debug、purge master log 和set global | 
| select | 查看表 | 
| insert | 插入权限 | 
| update | 修改表数据 | 
| delete | 删除行权限 | 
| alter | 修改表的结构 | 
| alter routine | 更改或者删除存储函数或者存储过程,隐式包含drop的权限 | 
| create | 创建表的权限 | 
| drop | 删除库,表,索引,视图 | 
| create routine | 创建存储函数或者存储过程的权限 | 
| create temporay tables | 创建临时表 | 
| create view | 创建视图 | 
| create user | 创建用户 | 
| show database | 查看拥有的数据库 | 
| index | 必须拥有index权限,才能执行create index或者drop index | 
| show view | 查看视图 | 
| excute | 以用户执行存储过程的权限 | 
| event | 表示拥有创建,修改,执行和删除事件(event)的权限。 | 
| lock tables | 锁表的权限 | 
| references | 用户可以将其他的一个字段作为某一个表的外键约束 | 
| reload | 必须拥有reload权限,才能flush tables logs privileges | 
| replication client | 拥有此权限可以查询到masterserver,slaveserver状态 | 
| replication slave | 拥有此权限可以查看从服务器,从主服务器读取二进制日志 | 
| shutdown | 关闭mysql的权限 | 
| grant option | 拥有grant option,就可以将自己拥有的权限授予给其他用户 | 
| process | 查看所有用户线程/连接的权限 | 
| all privileges | 影响除 with grant option 之外的所有权限 | 
管理权限也就是全局权限(如 super, process, file等)不能够指定某个数据库,on后面必须跟 *.*
 其实truncate权限就是create+drop,这点需要注意
五、资源限制
资源限制可以从以下4个方面限制
- 帐户每小时可发出的查询数量
- 帐户每小时可以发布的更新次数
- 帐户每小时可以连接到服务器的次数
- 帐户同时连接到服务器的数量
5.1 用户创建指定配额
mysql> create user 'test4'@'localhost' identified by '123456' WITH MAX_QUERIES_PER_HOUR 2 MAX_UPDATES_PER_HOUR 10 MAX_CONNECTIONS_PER_HOUR 5 MAX_USER_CONNECTIONS 2;
Query OK, 0 rows affected (0.03 sec)
5.2 修改配额
mysql> alter user 'test4'@'localhost' with MAX_QUERIES_PER_HOUR 100;
Query OK, 0 rows affected (0.01 sec)
六、案例
6.1 断开已删除用户
某个用户已经被我们删除了,但是已经通过该用户连接进来的是不受影响的。那么如何清理掉这些用户,断开连接呢?
查询已经删除用户id,生成SQL
mysql> select concat('kill ',id,';') from information_schema.processlist where user='root' into outfile '/tmp/kill.sql';
ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement
报错原因: 没有指定secure_file_priv参数
 解决方法: secure_file_priv是MySQL中的一个系统变量,用于限制LOAD DATA INFILE和SELECT … INTO OUTFILE语句的文件读写权限。它指定了允许从哪个目录中读取或写入文件。开启secure_file_priv参数,须在配置文件中修改,并重启数据库。
查询secure_file_priv参数,当前参数值为null
mysql> select @@secure_file_priv;
+--------------------+
| @@secure_file_priv |
+--------------------+
| NULL            |
+--------------------+
1 row in set (0.00 sec)
修改my,cnf配置文件,重启mysql
[root@mysql2 bin]# vim /etc/my.cnf 
secure_file_priv=/tmp/
重新查询secure_file_priv参数,当前参数值为/tmp/
mysql> select @@secure_file_priv;
+--------------------+
| @@secure_file_priv |
+--------------------+
| /tmp/              |
+--------------------+
1 row in set (0.00 sec)
继续查询清理的用户id,生成SQL
mysql> select concat('kill ',id,';') from information_schema.processlist where user='root' into outfile '/tmp/kill.sql';
Query OK, 1 row affected (0.00 sec)
mysql> source /tmp/kill.sql
七、MySQL 8.0 关于用户和权限新特征
后续更新慢慢更新ing......














![[oeasy]python0136_接收输入_input函数_字符串_str](https://img-blog.csdnimg.cn/img_convert/edd107bbd2d79474a101a833c7509475.png)



