前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >你还在使用set password修改密码吗?

你还在使用set password修改密码吗?

作者头像
数据库交流
发布2023-09-01 10:58:41
2450
发布2023-09-01 10:58:41
举报
文章被收录于专栏:悦专栏悦专栏

背景

我们有一套新的数据库账号管理平台,可以在界面上修改纳管的 MySQL 密码。然后我点了一下修改密码,报错了,在我的数据库某个组件的错误日志里有如下记录:

代码语言:javascript
复制
get an error packet for stmt set password for 'fander'@'%' = 'K9xxxxx7y'.
get an error packet, 1044 (42000) Access denied for user 'agent'@'%' to database 'mysql', and try to send it to client.

这里,我们能看出两个问题:

  1. 这个数据库账号管理平台修改 MySQL 密码时调用的是 set password 语句
  2. 没有 mysql 库相关的权限,所以抛出相关异常了

为什么还有人使用set password?

很多关系型数据库修改用户密码都是用 alter user 语法来做的,例如 PG

代码语言:javascript
复制
alter user 用户名 password "密码";

而 MySQL 在 5.6 及之前版本居然是不支持这种 alter user 语法修改密码的。他使用 set password 语法修改密码。

MySQL非常有个性~ PG说:“set password 是个什么鬼?”

用法如下:

代码语言:javascript
复制
# 修改当前登录用户
set password = password('密码');

# 修改其他用户
set password for 用户名 = password('密码');

MySQL5.6 是不支持 alter user 语法吗?

答案是否的,请看这张图。

从官方文档可以看出,5.6 版本 alter user 十分鸡肋,几乎啥都干不了,只能用于设置用户的密码过期。从5.7版本开始 alter user 才能用于修改密码,并且扩展出很多功能。

所以,5.6 不是不支持 alter user 语法,准确来说,是 5.6 不支持使用 alter user 语法修改用户密码。

回过头来,为什么这套新的数据库账号管理平台,采用 set password 来修改 MySQL 数据库的密码?我猜因为兼容性!set password 语法支持 5.6、5.7、8.0 三个版本的数据库修改密码,而 alter user 语法不支持 5.6 版本修改密码。看起来是这样的(后面会反转)。

我的推荐 alter user 的理由

1. alter user语法是事实标准

前面说了,PG 等数据库只支持 alter user 语法修改数据库用户密码,set password 是个什么鬼?

2. 官方也推荐

官方没有删除 set password 语法,但官方推荐使用 alter user 修改密码,替代 set password

3. 支持更合理的权限

无论使用 set password 还是 alter user 语法来修改当前登录用户的密码,都不需要额外权限。简单的说,你能登录则能改自己的密码。但如果想修改别人的密码,那么需要额外的权限,set passwordalter user 需要的权限是不一样的。

set password 需要什么权限?

官方答案是 update on mysql.* (可能是具体到某些表就可以了,没深入测试) 我们来做个实验:

代码语言:javascript
复制
# 此例子,使用 5.6 或 5.7 版本测试都可以

# 使用 root 登录,建两个测试用户
mysql -uroot -p -h127.0.0.1

    # 创建只持有 update on mysql.* 权限的 testsetpassword 用户
    mysql> create user testsetpassword identified by 'Fander@2023';
    Query OK, 0 rows affected (0.01 sec)
    mysql> grant update on mysql.* to testsetpassword;
    Query OK, 0 rows affected (0.00 sec)

    # 创建用于被测试修改密码的 testuser 用户
    mysql> create user testuser@'%' identified by 'Fander@2023';
    Query OK, 0 rows affected (0.01 sec)

# 使用 setpassworduser 用户登录数据库
mysql -usetpassworduser -pFander@2023 -h127.0.0.1

    # 使用 set password 语法修改密码,成功!
    mysql> set password for testuser@'%'=password('Fander@9999');
    Query OK, 0 rows affected (0.00 sec)
alter user 需要什么权限?

官方答案是 create user on *.* 或者 update on mysql.* 我们来做个实验1,验证单独给 create user 权限:

代码语言:javascript
复制
# 此例子,使用 5.6 或 5.7 版本测试都可以

# 使用 root 登录,建两个测试用户
mysql -uroot -p -h127.0.0.1

    # 创建只持有 create user 权限的 testalteruser 用户
    mysql> create user testalteruser identified by 'Fander@2023';
    Query OK, 0 rows affected (0.01 sec)
    mysql> grant create user on *.* to testalteruser;
    Query OK, 0 rows affected (0.00 sec)

    # 创建用于被测试修改密码的 testuser 用户
    mysql> create user testuser@'%' identified by 'Fander@2023';
    Query OK, 0 rows affected (0.01 sec)

# 使用 testalteruser 用户登录数据库
mysql -utestalteruser -pFander@2023 -h127.0.0.1

    mysql> show grants for current_user;
    +-------------------------------------------------+
    | Grants for testalteruser@%                      |
    +-------------------------------------------------+
    | GRANT CREATE USER ON *.* TO 'testalteruser'@'%' |
    +-------------------------------------------------+
    1 row in set (0.00 sec)

    # 使用 alter user 语法修改密码,成功!
    mysql> alter user testuser@'%' identified by 'Fander@9999';
    Query OK, 0 rows affected (0.00 sec)

同样的方法,我们来做个实验2,验证单独给 update on mysql. 权限:

代码语言:javascript
复制
# 此例子,使用 5.6 或 5.7 版本测试都可以

# 使用 root 登录,重新创建 testalteruser 用户
mysql -uroot -p -h127.0.0.1

    # 重新创建只持有 update on mysql.* 权限的 testalteruser 用户
    mysql> drop user testalteruser ;
    Query OK, 0 rows affected (0.00 sec) 
    mysql> create user testalteruser identified by 'Fander@2023';
    Query OK, 0 rows affected (0.01 sec)
    mysql> grant update on mysql.* to testalteruser;
    Query OK, 0 rows affected (0.00 sec)

# 使用 testalteruser 用户登录数据库
mysql -utestalteruser -pFander@2023 -h127.0.0.1

    mysql> show grants for current_user;
    +--------------------------------------------------+
    | Grants for testalteruser@%                       |
    +--------------------------------------------------+
    | GRANT USAGE ON *.* TO 'testalteruser'@'%'        |
    | GRANT UPDATE ON `mysql`.* TO 'testalteruser'@'%' |
    +--------------------------------------------------+
    2 rows in set (0.00 sec)

    # 使用 alter user 语法修改密码,成功!
    mysql> alter user testuser@'%' identified by 'Fander@9999';
    Query OK, 0 rows affected (0.00 sec)

在权限设置上,使用 alter user 语法我建议采用 create user 这个权限,而不是使用 update on mysql.* 这个权限(虽然官方文档说了,我们刚才也验证了这个权限也可以)。

理由是,create user 权限可以用于创建、修改、删除用户,他的权限更大一些,修改密码只是其中"修改用户"的一个小项功能而已。修改别的用户的密码一般就是数据库用户管理员的人了,给他 create user 权限,是更大一些,但逻辑上是合理的。

当然了,你实在奇奇怪怪,只想给这个数据库用户管理员 alter user 语法权限(修改用户权限)而已,是可以只给 update on mysql.* 啦,遗憾的是,这个权限看起来非常不直观了。

我没有测试 8.0 ,以上说法可能不适用于 8.0。

4. set password 语法在不同版本支持的选项有区别

set password 语法在三个大版本中有修改和变化,事实上会有兼容性问题,如图

我们可以看出 5.6 版本 set password 语法是必须使用 password 函数的。

代码语言:javascript
复制
# 5.6 正确写法
mysql> set password for testuser@'%'=password('Fander@9999');

# 5.6 错误写法
mysql> set password for testuser@'%'='Fander@9999';
ERROR 1372 (HY000): Password hash should be a 41-digit hexadecimal number

5.7 版本 set password 语法既支持使用 password 函数也支持直接接密码字符串, 使用 password 函数会收到警告提示"此功能将会弃用"。

代码语言:javascript
复制
mysql> set password for testuser@'%'='Fander@9999';
Query OK, 0 rows affected (0.00 sec)

mysql> set password for testuser@'%'=password('Fander@9999');
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> show warnings;
+---------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level   | Code | Message                                                                                                                                                                                 |
+---------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Warning | 1287 | 'SET PASSWORD FOR <user> = PASSWORD('<plaintext_password>')' is deprecated and will be removed in a future release. Please use SET PASSWORD FOR <user> = '<plaintext_password>' instead |
+---------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

8.0 版本 password 函数用法真的弃用了,抛出语法错误异常。

代码语言:javascript
复制
mysql> set password for testuser@'%'='Fander@9999';
Query OK, 0 rows affected (0.00 sec)

mysql> set password for testuser@'%'=password('Fander@9999');
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'password('Fander@9999')' at line 1

回过头来

我们回过头来,看看第一章节"背景"提出的问题

实际上,我们的这套数据库账号管理平台的 agent@'%' 持有的权限就是我建议的 create user 权限,我并没有给他赋权 update on mysql.* 权限,我们使用 alter user 语句修改密码时权限是足够的,但如果使用 set password 语句修改密码那就是权限不足的。

代码语言:javascript
复制
    mysql> show grants for agent@'%';
    +-------------------------------------------------+
    | Grants for agent@'%'                            |
    +-------------------------------------------------+
    | GRANT CREATE USER ON *.* TO agent@'%'           |
    +-------------------------------------------------+
    1 row in set (0.00 sec)

应用系统使用了 set password 语法和对应的 update on mysql.* 授权,前面我猜测是为了兼容 5.6 修改密码,对吧?其实不对的,因为按细分来说,应用系统使用的是 set password =auth_string 语法,这个 5.6 本身就不支持的(上图)。所以他们使用了 set password 语法根本不是为了兼容 5.6 版本。

所以要真的兼容 5.6 版本,应用系统是要分逻辑判断的

代码语言:javascript
复制
if 5.6 版本 then: 
    set password =password(auth_string)
if 5.7、8.0 then: 
    set password =auth_string
    #或者 alter user xxx identified by '密码'

我们线上有 MySQL5.6 版本吗?我们没有,官方也没有,MySQL5.6 早就 End of Life,不维护了啊!

所以我认为问题的最优解是,开发这套这套数据库账号管理平台的应用厂商,把底层修改数据库密码的逻辑从 set password 语法 改为使用 alter user 语法。

由于应用发版需要时间,而且这个只是个优化建议,别人不一定能接受。所以,我的临时解决办法,就是给 agent@'%' 补一个 update on mysql.* 授权,数据库账号管理平台修改密码的功能就正常了。

代码语言:javascript
复制
    mysql> show grants for agent@'%';
    +-------------------------------------------------+
    | Grants for agent@'%'                            |
    +-------------------------------------------------+
    | GRANT CREATE USER ON *.* TO agent@'%'           |
    | GRANT UPDATE ON `mysql`.* TO agent@'%'          |
    +-------------------------------------------------+
    1 row in set (0.00 sec)

最后,请忘记 set password,拥抱 alter user 吧。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-03-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 悦专栏 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 为什么还有人使用set password?
    • MySQL5.6 是不支持 alter user 语法吗?
    • 我的推荐 alter user 的理由
      • 1. alter user语法是事实标准
        • 2. 官方也推荐
          • 3. 支持更合理的权限
            • set password 需要什么权限?
            • alter user 需要什么权限?
          • 4. set password 语法在不同版本支持的选项有区别
          • 回过头来
          相关产品与服务
          数据库
          云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档