应使用show grants for 'user'@'host'导出权限,因其能完整生成库级、表级、列级等所有可执行授权语句;直接查mysql.user表仅含全局权限且字段复杂,易遗漏。

MySQL导出所有用户权限用SHOW GRANTS还是mysql.user表?
直接查mysql.user表不行——它只存全局权限,且字段含义复杂(比如Select_priv是'Y'/'N',但max_questions等限制值又得单独处理),手动拼SQL极易漏掉库级、表级、列级权限。真正可靠的方式是让MySQL自己生成可执行的授权语句:SHOW GRANTS FOR 'user'@'host'才是权威来源。
实操建议:
- 别用
SELECT * FROM mysql.user导出权限,那只是半截权限 - 对每个用户逐条执行
SHOW GRANTS FOR 'u1'@'localhost',再重定向到文件 - 注意:必须用有
SELECT权限的账号连接,否则SHOW GRANTS会报Access denied - 若用户数多,写个简单shell循环比手工敲快:
mysql -Nse "SELECT CONCAT('\'',user,'\'@\'',host,'\'') FROM mysql.user WHERE user!='' AND host!=''" | while read u; do echo "SHOW GRANTS FOR $u;"; done | mysql > grants.sql
导入权限脚本前为什么必须先DROP USER再CREATE USER?
迁移后直接source grants.sql大概率失败——因为GRANT语句要求用户已存在,而新库中用户可能根本不存在,或密码哈希格式不兼容(比如旧库是mysql_native_password,新库默认caching_sha2_password)。跳过这步,你会看到一堆ERROR 1133 (42000): Can't find any matching row in the user table。
实操建议:
- 导出时就补上
DROP USER和CREATE USER语句,不要依赖GRANT自动建用户 - 用
mysqldump --no-data --skip-triggers --compact mysql user导出原始用户记录,再转成CREATE USER语句(注意提取authentication_string和plugin字段) - 如果新库版本≥8.0,确认
CREATE USER语句里显式指定IDENTIFIED WITH caching_sha2_password BY 'xxx',否则可能因默认插件不匹配导致登录失败
grants.sql里哪些权限语句在新环境会静默失效?
不是所有SHOW GRANTS输出都能原样执行。最典型的是USAGE权限(空权限)和针对已删除数据库的权限——MySQL不会报错,但也不会生效;更麻烦的是PROXY权限、SET_USER_ID这类高危权限,在新库若未开启对应变量(如check_proxy_users=ON),导入后查不到错误,但实际不生效。
实操建议:
- 用
grep -v "USAGE" grants.sql > clean_grants.sql先过滤掉无意义语句 - 检查
grants.sql里是否有对不存在库/表的授权,比如GRANT SELECT ON `old_app`.* TO ...,新库没这个库就跳过整行 - 运行前在新库执行
SELECT @@global.check_proxy_users, @@global.proxy_user_privileges;,确认返回值为ON才导入含PROXY的语句 - 导入后立刻验证:
SELECT User,Host,Select_priv FROM mysql.user WHERE User='test';看是否真写进去了
为什么FLUSH PRIVILEGES有时候不生效?
在MySQL 5.7+,只要用GRANT/CREATE USER等DDL操作修改权限,服务端会自动重载权限表,FLUSH PRIVILEGES纯属多余;但如果用INSERT INTO mysql.user这种DML方式改表,才需要它。迁移时若混用两种方式(比如先INSERT再GRANT),FLUSH反而可能把刚GRANT的权限冲掉。
实操建议:
- 全程只用
GRANT/CREATE USER/DROP USER,完全不用INSERT或UPDATE操作mysql系统表 - 导入脚本末尾加
FLUSH PRIVILEGES;是安全冗余,但不是必须 - 如果导入后权限异常,优先怀疑是不是
CREATE USER语句里的IDENTIFIED WITH插件名拼错了,而不是FLUSH没执行
权限迁移真正的复杂点不在命令本身,而在用户身份映射——比如旧库有'app'@'%'和'app'@'192.168.1.%'两个同名用户,新库IP段变了,host条件得同步调整,否则权限就丢了。











