想搞清楚MySQL怎么获得权限,首先要明白一个前提:权限不会凭空产生,它必须被显式地授予某个账号。新创建的MySQL用户默认几乎什么都做不了,连接上服务器后执行SHOW DATABASES可能只看到一个information_schema库。很多人误以为创建用户之后就自动拥有了操作权限,其实创建用户和授予权限在MySQL中是两个独立的操作。只有通过GRANT语句把特定权限写到系统权限表中,用户才能真正执行对应的SQL操作。

MySQL的权限体系分成多个层级,从高到低依次是全局权限、数据库权限、表权限、列权限以及存储过程权限。全局权限保存在mysql.user表里,数据库权限保存在mysql.db表里,表权限和列权限则分别记录在mysql.tables_priv和mysql.columns_priv表中。当用户执行一条SQL语句时,MySQL会按照这个层级从上往下依次检查,只要在某一层找到了允许的权限,就不再继续往下找。例如用户被授予了全局SELECT权限,那么他对所有库的所有表都能查询,而不需要再逐一为每个库单独授权。理解这个层级关系,就能看懂为什么有时给库级权限就够了,有时却必须给全局权限。
先查看当前用户拥有哪些权限
在授权之前,推荐先学会查看已有权限。最直接的方法是使用SHOW GRANTS命令。如果你以root身份登录,执行SHOW GRANTS FOR 'someuser'@'localhost';就能完整列出该账号被授予的所有权限,输出结果是一段段GRANT语句。这些语句本身就是MySQL记录权限的原始形式,即使你忘记了当初怎么授权的,通过SHOW GRANTS也能还原出来。对于当前登录的用户,可以简写成SHOW GRANTS;,不过要小心它展示的只是当前连接所使用的账号对应的权限。
除了SHOW GRANTS,也可以直接查询系统表。比如查看某个用户是否具有全局SELECT权限,可以执行SELECT Select_priv FROM mysql.user WHERE User='someuser' AND Host='localhost';。如果返回Y表示有权限,N表示没有。但直接操作mysql系统表风险较大,一旦误改可能导致整个实例的权限混乱,生产环境不建议手动UPDATE这些表,而是统一使用GRANT和REVOKE语句。需要查看某张表上的权限时,可以查mysql.tables_priv表,其中的Table_priv列记录着逗号分隔的权限列表。
使用GRANT语句授予权限
GRANT是MySQL中分配权限的核心命令,语法结构为GRANT 权限列表 ON 对象 TO 用户。其中权限列表可以是单个权限如SELECT,也可以是多个权限用逗号隔开,例如SELECT, INSERT, UPDATE。对象部分用来限定权限作用的范围,常见写法有*.*表示全局所有库所有表,dbname.*表示某个数据库下的所有表,dbname.tablename表示指定库下的指定表。用户部分必须写成'username'@'host'的格式,host表示允许从哪台主机登录,localhost代表仅限本机,%代表任意远程主机。
给开发同事创建一个只读账号,只需要执行一条语句:GRANT SELECT ON mydb.* TO 'dev_read'@'%';。执行成功后,该用户就能查询mydb库中所有表的数据,但无法执行插入、更新或删除操作。如果还需要让他查看表结构,可以加上SHOW VIEW权限:GRANT SELECT, SHOW VIEW ON mydb.* TO 'dev_read'@'%';。对于更细粒度的控制,可以只授权某一张表:GRANT SELECT ON mydb.sales_records TO 'audit_user'@'localhost';。列级授权则用括号指定列名,例如只允许查看员工表的姓名和部门列:GRANT SELECT (name, department) ON company.employees TO 'hr_assistant'@'localhost';。
还有一种常见的需求是把某个数据库的全部操作权限交给一个运维人员,可以使用GRANT ALL PRIVILEGES ON appdb.* TO 'ops_user'@'%';。这里的ALL PRIVILEGES是一个快捷方式,代表该层级上的全部可用权限,但要注意它并不包括GRANT OPTION,也就是说被授权者自己不能再把权限转授给别人。如果需要让某个管理员能继续给其他用户授权,必须在语句末尾加上WITH GRANT OPTION,例如GRANT ALL PRIVILEGES ON *.* TO 'superadmin'@'%' WITH GRANT OPTION;。这种带GRANT OPTION的授权要谨慎使用,因为权限扩散后不容易追踪。
-- 创建用户(如果尚未创建) CREATE USER 'dev_read'@'%' IDENTIFIED BY 'StrongPass123!'; -- 授予mydb库的只读权限 GRANT SELECT, SHOW VIEW ON mydb.* TO 'dev_read'@'%'; -- 查看授权结果 SHOW GRANTS FOR 'dev_read'@'%'; -- 输出类似: -- GRANT SELECT, SHOW VIEW ON `mydb`.* TO `dev_read`@`%`
撤销权限与常见误区
权限可以授予就能收回,REVOKE语句的语法与GRANT基本对称。REVOKE SELECT ON mydb.* FROM 'dev_read'@'%';会撤销该用户对mydb库所有表的SELECT权限。如果只想撤销某一张表的权限,把对象换成mydb.sales_records即可。撤销全部权限可以使用REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'someuser'@'%';,这样能一次性清空该账号被授予的所有权限,但不会删除用户本身。删除用户需要执行DROP USER 'someuser'@'%';,两个操作不要混淆。
很多人在授权或撤销之后都会习惯性地执行FLUSH PRIVILEGES;,但事实上,从MySQL 5.7版本开始,通过GRANT和REVOKE语句修改权限时,MySQL会自动更新内存中的权限缓存,无需手动刷新。只有当你直接修改了mysql.user等系统表,才需要执行FLUSH PRIVILEGES让改动生效。这个命令本质上是从系统表中重新加载权限数据到内存,并不是授权流程的必选项。由于直接修改系统表风险很高,正常场景下基本用不到FLUSH PRIVILEGES,如果在网上看到教程要求授权后必须执行该命令,大多是基于旧版本MySQL的惯性操作。
另一个常见误区是以为给用户授予了库级权限就自动拥有该库下新建表的权限。实际上,库级CREATE权限只代表可以对数据库执行CREATE操作,但新建的表默认权限并不会自动记录。例如执行GRANT CREATE ON mydb.* TO 'dev_user'@'%';后,该用户可以创建新表,但创建完成后他对新表可能只有部分权限,因为MySQL不会为新建表自动复制库级权限。如果希望用户对自己创建的表拥有完全控制,通常需要额外授予GRANT ALL PRIVILEGES ON mydb.* TO 'dev_user'@'%',或者确保库级权限中包含了CREATE、DROP、ALTER等需要的所有权限。排查权限问题时,先确认用户连接的主机是否与授权时的host匹配,不匹配会导致看上去授权成功但实际登录后仍然没有权限。