ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

MySQL创建用户与授权全解析:从命令到权限管理最佳实践

MySQL创建用户与授权全解析:从命令到权限管理最佳实践 做开发或者运维的人几乎都遇到过这个场景项目马上要上线了需要给同事或者应用创建数据库账号分配某个库的读写权限。听起来特别简单但真到了执行的时候一堆问题就冒出来了——建了用户却登录不上、授权了却报权限不足、远程连不上数据库、MySQL 8.0 的认证插件跟老客户端不兼容……每一件都让人头大。这篇内容主要就围绕“创建用户并授权”这件事把完整的命令、底层逻辑和常见坑一次讲清楚。内容不绕弯子该给的命令直接给该解释的原理也顺手解释掉。适合刚接触 MySQL 的开发者照着抄也适合需要经常维护环境的 DBA 或运维同学作为速查手册收藏。1. 动手之前先确认版本和账号体系1.1 版本不同玩法就有差异MySQL 的命令整体上比较稳定但 5.7 和 8.0 之间还是有几个关键区别直接影响你后面写的每一条 SQL。先说一下最典型的差异点MySQL 8.0 默认使用caching_sha2_password认证插件而 5.7 默认是mysql_native_password。如果你用的客户端版本太老连到 8.0 上会直接报认证失败。MySQL 8.0 里面GRANT语句不能再顺带创建用户了。也就是说GRANT ALL ON *.* TO userhost IDENTIFIED BY password这种写法在 8.0 里面直接报语法错误必须先CREATE USER再执行GRANT。密码校验策略的默认强度不一样8.0 的validate_password组件在不少版本里是默认安装且启用的设置的密码太简单根本建不出来。所以在动手之前第一步不是急着写命令而是确认你面前的数据库是哪个版本。命令很简单SELECT VERSION();如果是 8.0后面的操作就按 8.0 的规则来如果是 5.7你有更自由的写法。很多网上搜到的命令是 5.7 时代的产物直接贴到 8.0 上会报错并不是你记错了是版本差异的问题。1.2 MySQL 账号不是“用户名密码”这么简单刚接触 MySQL 的人最容易忽略一个点MySQL 账号的全名是由用户名 主机两部分组成的格式是userhost。这里的 host 不是数据库服务器自己的主机名而是指“允许从哪个客户端主机使用这个账号登录”。同一个用户名只要 host 不同就是两个完全独立的账号密码可以不同、权限可以不同、互不影响。举个例子CREATE USER applocalhost IDENTIFIED BY pass123; CREATE USER app% IDENTIFIED BY pass456;上面两条命令创建了app这个用户分别对应 localhost 来源和任意来源的账号密码都不一样。客户端从本地连接时匹配的是第一条从远程连接时匹配的是第二条。这个机制是 MySQL 权限体系的地基。后面你做的所有授权、改密码、删用户操作都必须带上 host 才能精确命中目标账号。写DROP USER app是不合法的必须写DROP USER applocalhost这种完整写法。很多人在删除用户时发现报错原因就是没带 host。1.3 先确认 root 能不能顺利登录创建、授权、修改权限这些操作都需要当前账号具备相应的管理权限。绝大多数情况下你是用 root 登录来做的。如果你刚装好 MySQLroot 登录不上去常见的处理方式有这么几种没设过密码的话试试直接回车或者用sudo mysql免密登录。很多 Linux 发行版通过 auth_socket 插件认证 root本地以操作系统 root 身份执行sudo mysql就能直接进去。如果忘记密码需要在skip-grant-tables模式下临时启动 MySQL 服务进去以后修改 root 密码正常重启服务。这个过程网上教程很多这里不展开。我给你的建议是给 root 设一个高强度的密码并且只允许本地登录。日常业务操作不要用 root专门创建业务账号来做。这是维护 MySQL 最基本的安全习惯后面的所有授权操作都围绕这个原则展开。2. 创建用户CREATE USER 完整说明2.1 最基础的创建语句MySQL 8.0 和 5.7 都支持的标准创建用户语法是CREATE USER usernamehost IDENTIFIED BY password;三个位置分别解释一下username登录用户名一般只包含字母、数字、下划线。host允许登录的主机范围。常见取值localhost仅本机可以连接。%允许任意主机连接。192.168.1.%允许某个网段连接。192.168.1.100允许单个 IP 连接。password登录密码建议使用强密码。如果密码里包含特殊字符直接用单引号包裹就行。一个最典型的例子CREATE USER applocalhost IDENTIFIED BY App2024#Secure;执行成功后会返回Query OK, 0 rows affected这么简单就够了不需要额外刷新权限。用CREATE USER创建用户的场景下MySQL 会自动将账号信息写入系统权限表后面不用再执行FLUSH PRIVILEGES。2.2 IDENTIFIED BY 的各种细节密码部分有几种特殊情况值得单独拿出来讲。第一种如果你暂时不知道要设什么密码可以先建一个不设密码的账号。语法上IDENTIFIED BY 是允许的但我强烈不建议在生产环境这么干。密码为空等于给攻击者打开大门。第二种MySQL 8.0 里可以通过IDENTIFIED WITH ... BY ...来显式指定认证插件。比如你要兼容老客户端可以这样写CREATE USER app% IDENTIFIED WITH mysql_native_password BY App2024#Secure;这样写的好处是绕过 8.0 默认的caching_sha2_password让老的 PHP、Java 或 Python 客户端可以正常连接。但这只是兼容性临时方案从安全角度仍然推荐使用默认认证插件能换客户端就别将就认证插件。第三种MySQL 8.0 的默认密码规则经常让人“明明设了很复杂的密码还是提示不满足要求”。如果你确实需要临时收紧或放宽密码策略可以查看当前策略SHOW VARIABLES LIKE validate_password%;如果只是想在一个偶尔使用的测试环境快速建号可以临时把校验等级调低比如SET GLOBAL validate_password.policy LOW; SET GLOBAL validate_password.length 6;注意这些是全局变量修改重启后会失效。生产环境不要这么搞。2.3 创建用户时最容易忽略的几个问题结合平时的经验创建用户这个简单的操作背后还有几个隐藏点。第一host不一定只写localhost或%。我见过不少团队图省事直接给所有账号配%结果数据库暴露在公网上被爆破成功导致数据被删。如果你确实只需要从公司内网访问那就把 host 写成具体网段或 IP比如10.10.0.%。这一点真的非常重要不值得用数据安全去换省事。第二一个用户在不同 host 下可以同时存在多个账号。比如应用同时有本机访问和远程访问需求你可以创建applocalhost和app%两个账号甚至可以给它们配不同的密码和权限。不要觉得重复创建是错的这是 MySQL 账号体系的设计方式。第三创建用户的账号本身需要有CREATE USER权限。如果你当前是用业务账号登录的很可能没有这个权限执行时会提示Access denied。这种情况一般通过 root 或具备高权限的管理账号来执行。3. 授权GRANT 语句和权限模型3.1 权限分类速查创建用户只是把账号建出来账号本身默认是没什么权限的。你需要明确告诉 MySQL“这个账号可以用哪些数据库资源、做到什么程度”。MySQL 的权限大概分成这几类权限作用范围说明SELECT数据库/表查询数据最常用的只读权限INSERT数据库/表插入数据UPDATE数据库/表更新数据DELETE数据库/表删除数据CREATE数据库/表创建数据库或表DROP数据库/表删除数据库或表危险权限ALTER表修改表结构INDEX表创建或删除索引REFERENCES表创建外键约束CREATE VIEW视图创建视图SHOW VIEW视图查看视图定义CREATE ROUTINE存储过程创建存储过程/函数ALTER ROUTINE存储过程修改或删除存储过程/函数EXECUTE存储过程执行存储过程或函数EVENT数据库创建/修改/删除定时事件TRIGGER表创建/删除触发器RELOAD全局执行 FLUSH 操作SHUTDOWN全局关闭数据库服务PROCESS全局查看其他用户的连接进程FILE全局读取或写入服务器文件SUPER全局高级管理操作如 SET GLOBALCREATE USER全局创建/修改/删除用户GRANT OPTION全局允许用户把自己的权限转授给其他用户ALL PRIVILEGES全局/库/表除 GRANT OPTION 以外所有普通权限不需要把上表全背下来但你要知道权限可以精确到列。比如只允许某个用户查看订单表的id、order_no两列不给看金额列。这在做合规场景下非常有用。虽然平时很少用但知道有这种粒度对理解 MySQL 权限体系会有帮助。3.2 GRANT 基本语法和常用写法GRANT 的核心语法是GRANT privilege1, privilege2 ON level TO userhost;其中level表示授权的资源范围常用写法有四种全局级别ON *.*表示所有数据库的所有对象。库级别ON app_db.*表示某个数据库下的所有对象。表级别ON app_db.orders表示某张表。列级别ON app_db.orders (id, order_no)表示某些列。比如给只读账号授权GRANT SELECT ON sales_db.* TO reader192.168.31.%;给应用账号授权增删改查GRANT SELECT, INSERT, UPDATE, DELETE ON app_db.* TO applocalhost;一次给全部权限GRANT ALL PRIVILEGES ON app_db.* TO dev%;ALL PRIVILEGES不包括GRANT OPTION所以如果要让这个用户能继续给别人授权还必须单独加一下GRANT ALL PRIVILEGES ON app_db.* TO dev% WITH GRANT OPTION;WITH GRANT OPTION是一个非常危险的东西。它是把授权能力也交给了对方意味着他可以把这些权限转授给任何其他用户。生产环境尽量少用。授权完成后不需要执行FLUSH PRIVILEGES。GRANT 语句执行时MySQL 就会更新内存中的权限数据新权限立即生效。3.3 授权粒度什么时候用全局什么时候用库级我见过不少团队为了省事直接来一句GRANT ALL PRIVILEGES ON *.* TO app%;这种用法外包测试环境就算了如果在生产环境这样干等于把数据库完全暴露给应用层。一旦应用被注入攻击者拿到的就是整个数据库的管理权限。那正确的授权粒度怎么掌握我按场景给你拆一下数据分析师需要读线上业务数据只给相关库的 SELECT 权限最多加一个 SHOW VIEW。后端应用是某个业务系统的核心只给这个业务库的增删改查权限不要给 CREATE、ALTER、DROP。表结构变更应该走专门的迁移流程由 DBA 或 CI 脚本用管理员账号执行。前端或临时脚本只需要碰某一张表就只给这一张表的权限。定时任务需要调用存储过程给 EXECUTE 权限就够。这个思路用一个词概括就是最小权限原则。给用户多少权限只看他完成职责必须用到什么多一项都不给。这样可以最大化降低风险。3.4 查看授权结果授权不等于拍脑袋你最好把授权结果确认一遍。查看某个用户的完整权限用SHOW GRANTS FOR applocalhost;输出类似这样GRANT SELECT, INSERT, UPDATE, DELETE ON app_db.* TO applocalhost同时如果你想知道系统里所有账号当前有哪些权限也可以直接查系统库SELECT user, host, Select_priv, Insert_priv, Update_priv, Delete_priv FROM mysql.user;mysql.user 表里每个以_priv结尾的列代表一种全局权限。不过这张表对应的是全局权限如果你给某用户在库级或表级授权具体的授权关系会存到 mysql.db 或 mysql.tables_priv 表中。日常排查还是用 SHOW GRANTS 更直接。4. 权限修改、撤销与用户清理4.1 用 REVOKE 收回权限用户权限给多了或者某个同事离职了权限要及时收回来。回收权限的语法和 GRANT 对应REVOKE privilege_name ON db_name.* FROM userhost;收回所有权限REVOKE ALL PRIVILEGES, GRANT OPTION FROM userhost;举个例子之前给了某用户对 app_db 的所有权限现在你只想保留只读权限那就先把全部权限收回再单独授权 SELECTREVOKE ALL PRIVILEGES, GRANT OPTION ON app_db.* FROM dev%; GRANT SELECT ON app_db.* TO dev%;REVOKE 操作同样立即生效不需要 FLUSH。需要注意的是REVOKE 收回 GRANT OPTION 和普通权限但不会删除用户本身。用户还在只是变成“空权限”状态。这时候他依然能登录数据库只是看不到任何有权限的库。如果想让对方彻底无法登录直接删用户或者锁定账号。4.2 改密码和锁定账号MySQL 8.0 修改用户密码的标准做法是ALTER USERALTER USER applocalhost IDENTIFIED BY NewPass2025;如果你要兼容老客户端认证插件也可以改成ALTER USER applocalhost IDENTIFIED WITH mysql_native_password BY NewPass2025;MySQL 5.7 及更早的版本还有SET PASSWORD FOR这种写法在 8.0 里面同样可用但更推荐直接使用 ALTER USER语义更清晰。锁定账号也是个常用操作。临时不让某个用户登录不用删除账号直接加锁即可ALTER USER applocalhost ACCOUNT LOCK;解锁ALTER USER applocalhost ACCOUNT UNLOCK;这个功能特别适合处理“业务停了但账号以后可能还要用”的场景。比删了重新建少一步也避免密码策略重新折腾。4.3 删除用户DROP USER 和 DELETE 的真正区别彻底删除用户用DROP USER applocalhost;语法要求必须同时指定用户名和 host。这是最推荐的方式。当然也有一个古老的操作是用 DELETE 从 mysql.user 表删除记录DELETE FROM mysql.user WHERE user app AND host localhost; FLUSH PRIVILEGES;这个操作在线上不推荐。原因有两点一是你绕过了 MySQL 的权限管理工具直接改系统表出问题排查成本高二是 DELETE 之后如果不执行 FLUSH PRIVILEGESMySQL 内存里还是存在这个账号的权限缓存可能引发不明所以的权限跳变。DROP USER 不存在这种隐患。4.4 FLUSH PRIVILEGES 到底什么时候才需要这是新手最容易误解的地方。网上很多教程都会在 GRANT 后面加一句 FLUSH PRIVILEGES好像不刷新权限就不会生效。实际上只有在通过 INSERT、UPDATE、DELETE 直接修改了 mysql.user 等系统权限表的情况下才需要执行 FLUSH PRIVILEGES 重新加载权限表。而你用 CREATE USER、GRANT、REVOKE、DROP USER 这些标准权限管理语句操作时MySQL 会自动同步到内存和磁盘中完全不需要手动刷新。所以我的建议是忘掉网上那些老教程里的 FLUSH PRIVILEGES 吧保持一个干净的习惯。只有在你确实手工改过权限表时才执行一遍 FLUSH PRIVILEGES。5. 远程连接和 host 匹配机制5.1 远程连不上先查这三件事创建了一个app%的用户客户端从远程连接却提示连不上这是非常常见的问题。很多情况下并不是授权语句出了问题而是 MySQL 服务端根本没开远程监听。第一件事查 MySQL 的监听配置。默认情况下 MySQL 只监听本机地址配置在 my.cnf 或 my.ini 中。找到[mysqld]部分[mysqld] bind-address 0.0.0.0如果 bind-address 是127.0.0.1那远程永远连不上改成0.0.0.0表示监听所有网卡。另外确保没有启用skip-networking否则 MySQL 直接不监听 TCP 端口只允许本机通过 socket 文件连接。第二件事检查系统防火墙。MySQL 默认端口 3306如果操作系统防火墙没有放行这个端口远程连接同样失败。很多时候你在云服务器上还要额外在安全组中放行 3306 入口。第三件事确认账号的 host 设置。applocalhost只能在服务器本机登录远程必须用app%或app内网IP这种范围更宽的主机记录。这三件事按顺序排查基本能解决百分之九十的远程连接问题。5.2 host 匹配顺序的底层逻辑MySQL 在验证客户端连接时会从 mysql.user 表里找到匹配的账号记录。如果一个用户对应多条 host 记录MySQL 并不是随机挑一条而是按照“越精确的 host 越优先”的规则来匹配。匹配顺序大致是空主机名或 localhost具体 IP比如192.168.1.100网段比如192.168.1.%主机名%也就是说如果客户端从192.168.1.100连接而同时存在app192.168.1.100和app%两条记录MySQL 会优先使用具体 IP 的那条即使%那条是在后面创建的。理解了这一点你就能解释很多怪异现象。比如你建了一个app%并给了全库权限却发现客户端连上来查询还是提示没有权限。大概率是因为还存在一条更具体的 host 记录比如app192.168.1.%或applocalhost且那个账号权限更小。此时光改%对应的权限没用得找到真正被匹配到的那条记录或者直接把多余的 host 记录删掉。5.3 修改监听配置后的注意事项修改了 bind-address 或启用了 skip-networking 之后必须重启 MySQL 服务才能生效。命令根据系统不同有差异常见的有sudo systemctl restart mysql sudo systemctl restart mysqld如果重启报错先看日志一般是权限问题或配置文件格式问题。另外我强烈建议你在修改监听之前确认服务器所在网络环境公网服务器开启远程监听一定要搭配防火墙和强密码否则非常容易成为爆破目标。国内有很多扫描脚本在持续扫描公网数据库端口一旦暴露且密码弱数据很快就会被拖走。6. 高频实操场景直接抄作业6.1 场景一给数据分析师建只读账号数据分析师需要从某个业务库读数据但不能写也不能看其他库。执行CREATE USER analyst192.168.31.% IDENTIFIED BY Read2024; GRANT SELECT ON sales_db.* TO analyst192.168.31.%; GRANT SHOW VIEW ON sales_db.* TO analyst192.168.31.%;如果以后需要从公司任意内网地址访问host 可以改成10.0.0.%根据实际网段来定。不要轻易用%。SHOW VIEW 权限是给需要查看视图定义的分析师准备的。如果不需要忽略即可。6.2 场景二给 Web 应用建业务账号后端应用连接数据库需要增删改查一般只针对自己的业务库CREATE USER web_applocalhost IDENTIFIED BY WebApp2024!; GRANT SELECT, INSERT, UPDATE, DELETE ON app_db.* TO web_applocalhost;如果应用服务器和数据库服务器不是同一台则 host 写成应用服务器的 IP 或内网网段例如CREATE USER web_app10.10.2.18 IDENTIFIED BY WebApp2024!; GRANT SELECT, INSERT, UPDATE, DELETE ON app_db.* TO web_app10.10.2.18;不要给应用账号 CREATE、ALTER、DROP 之类的表结构权限。网上很多教程图省事直接GRANT ALL这在生产环境非常危险。一旦应用存在 SQL 注入漏洞攻击者可以借助这些权限删库重建后果不可控。6.3 场景三给独立开发者建单库最小权限账号如果是给外包团队或合作开发的同事开账号建议只给一个独立库的最小权限让他只能在这个范围内操作CREATE USER outsource192.168.100.% IDENTIFIED BY Outsource2024; GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, INDEX ON temp_project_db.* TO outsource192.168.100.%;这里我加了 CREATE、ALTER、INDEX是因为开发阶段通常需要自己建表和改表结构。这算是对外账号的一种折中方案既不暴露其他库也不会让他因为权限不足频繁找你加权限。项目结束或者合作终止后第一时间回收REVOKE ALL PRIVILEGES, GRANT OPTION ON temp_project_db.* FROM outsource192.168.100.%; DROP USER outsource192.168.100.%;6.4 场景四从多个主机访问同一个账号有些场景下同一个应用系统会从多台服务器连接数据库比如负载均衡后面的几台业务机。这时候你可以建多个 host 记录也可以直接用一个网段。网段写法更高效CREATE USER cluster_app10.10.1.% IDENTIFIED BY ClusterApp2024; GRANT SELECT, INSERT, UPDATE, DELETE ON cluster_db.* TO cluster_app10.10.1.%;如果只是几台固定 IP也可以分别建CREATE USER cluster_app10.10.1.11 IDENTIFIED BY ClusterApp2024; CREATE USER cluster_app10.10.1.12 IDENTIFIED BY ClusterApp2024;两条记录的用户名相同但 host 不同是允许存在的。这样能精确控制哪些机器能访问数据库比一个大网段更安全。6.5 场景五创建临时账号并设置过期时间临时给外部人员或测试环境开通账号可以设置密码过期时间避免长时间留存CREATE USER temp_tester% IDENTIFIED BY TempTest2024 PASSWORD EXPIRE INTERVAL 7 DAY; GRANT SELECT ON test_db.* TO temp_tester%;这样这个账号的密码 7 天后自动过期对方下次登录时必须修改密码否则无法使用。如果你希望一次性密码也可以写成CREATE USER one_time% IDENTIFIED BY OneTime2024 PASSWORD EXPIRE;首次登录时必须修改密码。这两种方式都适合临时授权场景比手动记着“过几天记得删”要可靠得多。6.6 场景六整理账号和权限清单系统跑久了账号可能越积越多。建议定期用下面几条 SQL 盘点一下账号情况-- 查看所有账号 SELECT user, host FROM mysql.user; -- 查看某账号的权限 SHOW GRANTS FOR web_applocalhost; -- 查看当前库下所有表级授权 SELECT * FROM mysql.tables_priv;顺手把长时间不用的账号锁定或删除这是很多团队容易忽视的维护动作。一个被遗忘的高权限账号往往是安全事件里最容易被利用的入口。7. 常见报错与排查经验速查7.1 Access denied ... (using password: YES)这个报错出现的频率极高意思是账号或密码不正确或者当前账号不允许从该主机登录。排查思路确认用户名和密码是否输错。别低估这个基础问题密码里带特殊字符时很容易手滑。确认 host 是否匹配。本地连接用applocalhost远程连接需要app192.168.x.x或app%。用 root 登录后执行SHOW GRANTS FOR applocalhost查看账号是否存在以及密码是否匹配。有一个比较反直觉的现象即使你已经给app%建好了账号客户端从某台机器连接时还是可能匹配到更精确的 host 记录。如果那条记录密码不同就会报 Access denied。所以排查时一定要看客户端实际从哪个 IP 连接再对应去查账号记录。7.2 Host xxx is not allowed to connect to this MySQL server这个报错基本可以断定是 host 匹配问题。客户端 IP 不在账号允许的范围内。解决方案就是修改账号的 host 范围RENAME USER applocalhost TO app%;或者创建一个新账号CREATE USER app客户端IP IDENTIFIED BY password; GRANT ... ON ... TO app客户端IP;注意 RENAME 会保留账号原有的权限创建新账号则需要重新授权。另外这个报错也可能是因为服务端根本没启动远程监听。按之前讲的先查 bind-address 和防火墙然后再去改账号 host。7.3 Authentication plugin caching_sha2_password cannot be loaded这是 MySQL 8.0 用户最常见的一个遗留问题。老版本的客户端工具或旧版语言驱动不认识 8.0 默认的认证插件报错会直接指向caching_sha2_password。处理方案有两个方案一升级客户端或驱动。这是最推荐的做法治本。MySQL 官方维护了很多语言连接器更新到匹配版本后问题自然消失。方案二为了兼容老客户端把用户认证方式改成mysql_native_passwordALTER USER applocalhost IDENTIFIED WITH mysql_native_password BY App2024;这个操作能把当前用户调回旧版认证插件代价是密码在服务端的哈希方式变成老算法。仅作为过渡方案使用长期来看还是要升级客户端避免在兼容性上越走越远。7.4 授权了但没生效排除掉 host 匹配问题之后还有一种可能性是当前账号连接时匹配到了多条记录而实际生效的是那条权限较小的。上面在讲解 host 匹配顺序时说过MySQL 优先匹配更具体的记录。比如你从192.168.1.88这台机器连接但是存在app192.168.1.%和app%两个账号。MySQL 会用网段那条记录去验证和授权而不是%。所以你给app%加的任何权限都不影响这个网段账号。解决办法就是精确找到客户端实际匹配的账号记录然后修改那一条。用下面的 SQL 检查SELECT user, host FROM mysql.user WHERE user app; SHOW GRANTS FOR app192.168.1.%;确认之后针对匹配到的记录重新授权即可。排查这类问题最忌讳想当然一定先把实际匹配关系弄清楚再动手改。7.5 给新手的排查清单为了偷懒我把常见问题整理成一个简单的排查顺序出现权限或连接问题时按这个顺序走一遍确认 MySQL 服务是否正常启动端口是否监听netstat -an | grep 3306。确认客户端连接时用的主机是否匹配账号的 host 范围。用 root 登录执行 SHOW GRANTS 查看目标账号的权限全貌。检查 bind-address 和 skip-networking 配置确认服务端允许远程连接。检查防火墙和云安全组确认 3306 端口对外可达。确认 MySQL 版本和认证插件兼容性。大多数权限相关的问题在这六个步骤内就能定位。最后说两句MySQL 创建用户和授权这件事确实不难但它值得你认真对待。根据我个人的经验和观察生产环境大部分数据库安全问题都不是因为数据库软件本身有漏洞而是因为账号权限给得太随意比如 root 密码太简单、业务账号带 DDL 权限、账号长期不清理。所以我的建议始终是权限给得小一点、账号用得专一点、变更记录留得全一点。每创建一个用户顺手把创建语句和授权语句记录下来放到项目的文档或配置管理工具里。下次换环境、恢复备份、复盘权限时这些记录能帮你省下大把时间。操作本身简单养成可追溯的习惯才是真正考验功力的地方。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进