在MySQL数据库的日常管理中,为不同业务创建独立账号并严格控制其操作范围,是保障数据安全的基本手段。很多团队图省事让所有服务都用root连接数据库,这种做法一旦程序被攻破,攻击者就能删库跑路。因此,理解MySQL的用户体系和授权机制是每个后端和运维人员必备的技能。

一、MySQL用户与权限体系基础
MySQL中的用户并不是单纯的用户名,而是由用户名@主机名共同构成的复合标识。主机名部分决定了该用户能从哪台机器连接数据库,可以是具体IP、网段(如192.168.0.%)、域名或通配符%。例如appuser@'127.0.0.1'和appuser@'192.168.0.1'在MySQL里是两个完全不同的账号,即使密码相同也互不影响。
权限信息存储在系统库mysql的多个表中,主要包括user表(全局权限)、db表(库级权限)、tables_priv表(表级权限)和columns_priv表(列级权限)。当我们执行授权命令时,MySQL实际是在修改这些表。在MySQL 8.0之后,已不再支持在GRANT语句中隐式创建用户,必须先用CREATE USER建好账号再授权,这避免了误建账号的风险。
二、创建MySQL用户的标准步骤
创建用户使用CREATE USER语句。最基本的形式是指定用户名、允许连接的主机以及身份验证方式和密码。以下示例创建一个只能从本地连接的用户,并使用MySQL 8.0默认的caching_sha2_password插件:
-- 创建本地访问用户,密码为StrongPass123 CREATE USER 'report_user'@'127.0.0.1' IDENTIFIED BY 'StrongPass123'; -- 若需兼容旧客户端,可显式指定旧版插件 CREATE USER 'legacy_user'@'192.168.0.1' IDENTIFIED WITH mysql_native_password BY 'LegacyPass456';
上面的代码中,IDENTIFIED BY后面是明文密码,MySQL会自动进行加密存储。如果希望用户通过操作系统认证或免密登录,可使用IDENTIFIED WITH auth_socket等方式,但生产环境通常不推荐。创建完成后,该用户此时没有任何权限,连show databases都执行不了。
我们还可以限制用户资源,比如每小时最大查询数、连接数等,防止单个账号耗尽数据库资源:
-- 限制每小时最多100次查询和20个并发连接
CREATE USER 'api_user'@'192.168.0.%'
IDENTIFIED BY 'ApiPass789'
WITH MAX_QUERIES_PER_HOUR 100
MAX_USER_CONNECTIONS 20;
三、分配权限的GRANT用法详解
GRANT命令用来把特定权限赋予指定用户。权限粒度从全局到列级有多层,常见权限包括SELECT、INSERT、UPDATE、DELETE、CREATE、DROP、ALL PRIVILEGES等。下面给出几个典型授权场景:
-- 授予某个库下所有表的只读权限 GRANT SELECT ON shop_db.* TO 'report_user'@'127.0.0.1'; -- 授予业务库完整的增删改查及结构修改权限 GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER ON shop_db.* TO 'api_user'@'192.168.0.%'; -- 授予全局所有权限(相当于root,谨慎使用) GRANT ALL PRIVILEGES ON *.* TO 'admin_user'@'localhost' WITH GRANT OPTION;
注意ON 库名.表名的写法,星号代表所有。WITH GRANT OPTION表示被授权者可以把自己的权限再转授他人,一般只给管理员。在MySQL 8.0中,执行GRANT前用户必须存在,否则会报错,这与5.7及之前版本不同。
授权后需要让MySQL重新加载权限表才能生效。虽然大部分情况下MySQL会自动刷新,但在修改了mysql库底层表或想确保即时生效时,应手动执行:
-- 刷新权限使改动立即生效 FLUSH PRIVILEGES;
四、查看与撤销权限
使用SHOW GRANTS可以检查某个用户当前拥有哪些权限,这在排查访问拒绝错误时非常有用:
-- 查看指定用户的授权情况 SHOW GRANTS FOR 'api_user'@'192.168.0.%'; -- 查看当前登录用户的权限 SHOW GRANTS;
当员工离职或业务下线时,应及时收回权限。REVOKE语句的语法与GRANT对应,只需把GRANT换成REVOKE、TO换成FROM:
-- 撤销业务用户的删除和结构修改权限 REVOKE DELETE, DROP ON shop_db.* FROM 'api_user'@'192.168.0.%'; -- 完全回收某用户所有权限但保留账号 REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'temp_user'@'127.0.0.1';
如果确定账号不再需要,直接用DROP USER删除即可,比单纯撤销权限更干净:
-- 删除指定用户 DROP USER 'temp_user'@'127.0.0.1';
五、授权流程最佳实践
遵循最小权限原则是账号管理的铁律。应用账号只给业务必需的库表权限,禁止使用ALL PRIVILEGES;不同服务使用不同账号,避免一个泄露全盘崩;连接主机尽量限定具体IP或内网段,不用%公网开放。定期用SHOW GRANTS审计账号权限,结合慢查询日志发现异常行为。
对于需要程序自动化建用户的场景,建议将CREATE USER和GRANT写成脚本,并通过配置管理工具统一下发,避免人工在线上直接敲命令导致语法错误或权限过大。下表总结了常用权限级别与典型使用角色:
| 权限级别 | 示例语句 | 适用角色 |
|---|---|---|
| 全局(*.*) | GRANT ALL ON *.* | 数据库管理员 |
| 库级(db.*) | GRANT SELECT ON shop_db.* | 报表、读库账号 |
| 表级(db.table) | GRANT UPDATE ON shop_db.orders | 特定业务模块 |
| 列级 | GRANT SELECT (col1) ON db.t | 隐私字段隔离 |
掌握上述创建用户与分配权限的完整流程后,你就能在MySQL中构建清晰、安全的多租户访问环境,从账号层面堵住大部分误操作与恶意入侵的口子。