ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

MySQL忘记密码重置:skip-grant-tables与init-file

MySQL忘记密码重置:skip-grant-tables与init-file 凌晨两点在群里看到消息说线上库连不上了翻遍交接文档也没找到 root 口令几个人围着跳板机干瞪眼——这种场面我在这些年里碰上过不止一次。MySQL 用户密码忘记这件事听起来像个小事真落到生产环境上处理不好就是一次实打实的故障。有经验的人二十分钟搞定没踩过坑的人能折腾一宿还可能在慌乱中把数据目录搞坏。这篇内容我想把 MySQL 忘记用户密码这件事从底层原理到落地操作完整讲一遍包括密码到底存在哪、8.0 和 5.7 为什么改法不同、跳过授权表这条路有什么隐患、--init-file方案怎么用以及 Docker、Windows 服务、托管数据库这些不同环境下的具体走法。适合正在学 MySQL 的新手也适合手上有库要维护但没做过密码恢复的老手照着做基本能复现。1. 先弄明白MySQL 的密码到底存在哪、怎么校验1.1 密码不在配置文件里而在系统库的授权表里很多人第一次遇到这个问题第一反应是去my.cnf或者my.ini里找密码翻半天只看到datadir、socket、port、max_connections这些配置项。原因很简单配置文件管的是服务器怎么跑不管谁能进来。真正的账号密码落在数据目录下的mysql系统库里具体就是mysql.user这张表里面有User、Host、authentication_string、plugin几列你登录时输入的密码服务器会按plugin指定的算法算出摘要再跟authentication_string里存的摘要比对。所以忘记密码这件事本质上不是找回一个字符串而是把authentication_string这个字段换成一个你知道的新值。理解这一点非常关键因为后面所有的重置方案不管走哪条路最终都是在做同一件事想办法把新的哈希写进这张表然后让服务器重新加载权限。8.0 版本做了一次数据字典重构mysql.user在信息架构上变成视图形式权限表结构也收得更紧官方明显不希望你再直接UPDATE mysql.user这也是为什么很多 5.6 时代的老教程在 8.0 上执行会直接报错。你可以用下面的语句先看一眼自己库里长什么样SELECT user, host, plugin, authentication_string FROM mysql.user;正常输出里通常会看到rootlocalhost、mysql.syslocalhost、mysql.sessionlocalhost这几行plugin列在 8.0 上大概率是caching_sha2_password在 5.7 上多为mysql_native_password。这一列信息很重要后面选重置语句的写法就靠它。1.2 认证插件这层是很多老教程翻车的地方MySQL 的密码校验不是简单比字符串而是走认证插件这套机制。5.7 时代主流是mysql_native_password用的是 SHA1 两轮散列8.0 换成了caching_sha2_password安全性更好但要求客户端支持对应的握手流程。问题就出在这如果你用 8.0 的密码策略重置了密码然后拿一个老版本的客户端工具去连很可能报Authentication plugin caching_sha2_password cannot be loaded看着像密码错了其实是被授权插件卡住了。还有一个变更点经常被忽略MySQL 5.7.6 之后mysql.user表里原来的password字段改名为authentication_string同时PASSWORD()函数被移除了。也就是说网上那些写着UPDATE mysql.user SET passwordPASSWORD(123456) WHERE userroot;的教程在 5.7.5 及以前能用之后直接报函数不存在。8.4 版本开始mysql_native_password插件默认关闭9.x 更是彻底移除这意味着以后新建用户只能用caching_sha2_password。把这些版本差异先记在心里后面写 SQL 的时候就不会抄错。1.3 忘记密码分两种情况处理路径完全不同这是我在实际处理时最先判断的一件事到底是一个能登的账号都没有还是只是某一个账号忘了密码。前者必须走离线重置得重启数据库后者其实一条ALTER USER就完了根本不用停机。这两种情况的成本差了几十倍动手前一定要先确认清楚别一上来就急着改配置文件重启服务。场景判断方法处理路径是否需要重启完全登不进去任何账号都报 1045跳过授权表或 init-file需要两次root 能登忘了普通账号root 登录后可查mysql.user直接ALTER USER不需要忘记 root但有其他管理员账号用管理员账号登录直接ALTER USER不需要忘了密码且库已停服务起不来冷备数据目录后离线重置需要现实中最常见的其实是第三种——很多团队会给运维同学单独开一个管理账号这时候只要用那个账号登录执行ALTER USER rootlocalhost IDENTIFIED BY 新密码;就结束了。反倒是完全进不去的情况才需要后面那一整套流程。此外还有一种隐蔽情况密码没忘但host匹配不上比如你从 192.168.1.50 连过去而账号建的是applocalhost也会报 1045这个误判我在排查时遇到过好几次。2. 动手之前的准备三件必须确认的事2.1 确认版本、部署方式和数据目录位置动手之前先把这三件事确认清楚能省掉后面一大半的返工。第一是版本mysql --version或者在能连上的情况下执行SELECT VERSION();5.7 和 8.0 的重置语句写法不同8.4 又另有变化。第二是部署方式是包管理器装的yum/apt、二进制解压的、还是容器跑的这决定了服务怎么停、参数怎么加。第三是数据目录和配置文件路径包管理器安装通常配置文件在/etc/my.cnf或/etc/mysql/my.cnf数据目录在/var/lib/mysql二进制安装则一般都在解压目录下。在 Linux 上我习惯用这几条命令一次性看清楚ps -ef | grep mysqld | grep -v grep systemctl status mysqld # Ubuntu/Debian 上服务名可能是 mysql mysql --help | grep -A1 Default options ls -ld /var/lib/mysql第一条看进程和实际加载的参数第二条看服务状态和 systemd unit 文件路径第三条能看出配置文件搜索顺序第四条看数据目录归属用户。特别提醒一下服务名RHEL 系一般是mysqldDebian/Ubuntu 系是mysql在国产 Linux 发行版上这两种命名都可能出现先systemctl list-units | grep -i mysql查一下再操作比凭印象敲命令靠谱得多。2.2 数据备份与回滚为什么这一步不能省正常情况下做备份很简单mysqldump一行命令搞定。可现在的问题是——你没密码dump 不出来。这是个死结很多人在这一步卡住然后心一横跳过备份直接改配置风险就埋下了。我的做法是做冷备先把服务停干净确认没有 mysqld 进程残留然后直接对整个数据目录做物理拷贝。systemctl stop mysqld ps -ef | grep mysqld | grep -v grep # 确认没残留 tar -czf /backup/mysql_datadir_$(date %F).tar.gz -C /var/lib mysql之所以要在停库之后拷是因为 InnoDB 有 redo log 和 undo log运行中直接拷文件会得到一份不一致的快照恢复起来麻烦。停库后拷贝虽然要停几分钟服务但拿到的一定是一致的。另外提醒一句tar的时候把整个datadir目录都带上包括ibdata1、ib_logfile*、mysql.ibd、undo_001这些别只挑业务库的目录权限表和数据字典都在里面。备份文件最好挪到另一块盘或者另一台机器上别原地放着磁盘出问题就一起没了。2.3 方案选型skip-grant-tables 和 init-file 怎么选两条主流路线我用一个表格对比一下方便按环境选对比项skip-grant-tablesinit-file原理启动时忽略权限表校验启动时执行指定 SQL 脚本操作步骤改配置、重启、手敲 SQL、再改回来、再重启写脚本、改启动参数、重启一次是否需要交互需要得手动执行 SQL不需要自动化友好生产环境友好度一般中间窗口期无鉴权较好一次启动即完成失败风险忘记改回配置会留下大坑脚本写错会导致启动失败适用版本5.5 到 9.x 全部支持5.5 到 9.x 全部支持我自己的习惯是临时救急、单机环境、能盯着屏幕的两小时内搞定用skip-grant-tables更快如果是生产环境、要走变更流程、还想把过程脚本化留下来用--init-file更稳。下面两节分别把两条路的完整操作写清楚。3. 方案一skip-grant-tables 跳过权限表3.1 让 MySQL 带着这个参数启动skip-grant-tables的作用是让服务器启动时不去读授权表任何账号都能无密码登录而且所有账号都被当成超级用户。让 MySQL 带上这个参数启动有三种常见做法从简单到规范排列。第一种直接改配置文件。在my.cnf的[mysqld]段落里加一行[mysqld] skip-grant-tables改完systemctl restart mysqld即可。这个方法最直白缺点是容易忘了删务必在改之前先记一笔待办。第二种用 systemd 的环境变量适合不想动配置文件的场景前提是 unit 文件里引用了MYSQLD_OPTSsystemctl set-environment MYSQLD_OPTS--skip-grant-tables systemctl start mysqld注意这个变量在 systemd 重启后会丢失正好可以利用这一点做自动清除。如果启动后发现参数没生效说明 unit 文件里没有EnvironmentFile或者没用$MYSQLD_OPTS得去看一眼systemctl cat mysqld。第三种用 override 覆盖最规范systemctl edit mysqld # 在打开的编辑器里写入 # [Service] # ExecStart # ExecStart/usr/sbin/mysqld --skip-grant-tables $MYSQLD_OPTS systemctl daemon-reload systemctl start mysqld这里必须把原来的ExecStart先清空再重写否则 systemd 会报重复定义。改完重置密码后systemctl revert mysqld就能把覆盖删掉比手动改配置文件干净。3.2 连上去改密码5.7 和 8.0 的写法不一样服务起来之后直接连密码那一步回车就行mysql -uroot如果 socket 路径不是默认的加上-S参数比如mysql -uroot -S /var/lib/mysql/mysql.sock。连上之后8.0 和 5.7 的写法差别就在这几行-- MySQL 8.0 及 8.4 的标准写法 FLUSH PRIVILEGES; ALTER USER rootlocalhost IDENTIFIED BY Str0ng_Pssw0rd!; -- MySQL 5.75.7.6 之后同样推荐用 ALTER USER FLUSH PRIVILEGES; ALTER USER rootlocalhost IDENTIFIED BY Str0ng_Pssw0rd!; -- 只有 MySQL 5.7.5 及以前才需要这种老写法 -- UPDATE mysql.user SET passwordPASSWORD(新密码) WHERE userroot; -- FLUSH PRIVILEGES;FLUSH PRIVILEGES这一句为什么必须放在前面值得解释一下。在跳过授权表模式下服务器启动时就没加载权限信息ALTER USER这类语句依赖权限子系统直接执行会报ERROR 1290 (HY000): The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement。而FLUSH PRIVILEGES会触发服务器重新读取授权表并启用权限检查之后 DDL 才能正常执行。至于为什么不建议直接改表一是 8.0 里权限表结构变了二是直接写摘要容易踩到插件的坑ALTER USER会自动调用对应插件来算哈希省心得多。3.3 改完之后必须做的收尾动作密码改完不代表结束收尾动作做漏了等于给库里留了一扇后门。按顺序来先退出客户端然后去掉启动参数再正常重启最后用新密码验证。mysql exit # 去掉 my.cnf 里的 skip-grant-tables或用 systemctl revert mysqld systemctl restart mysqld mysql -uroot -p -e SELECT user, host, plugin FROM mysql.user WHERE userroot;验证的时候顺带看一眼有没有空密码的账号和匿名用户SELECT user, host FROM mysql.user WHERE user OR authentication_string;如果有匿名账号直接DROP USER localhost;清掉。这一步是很多人会漏的因为库里曾经被优化过留了一堆匿名用户权限检查恢复正常后虽然不能直接用但留着终归是隐患。注意从启动跳过授权表的模式开始到重启回正常模式之间任何人只要能连到这个实例就能拿到全部权限。这段时间里务必断开公网访问用防火墙挡掉 3306或者干脆停掉业务入口改完立刻恢复。3.4 这条路上的坑网络监听、密码策略、连接方式第一个坑是网络监听。MySQL 8.0.11 之后开启skip-grant-tables会自动连带启用skip-networking服务器只监听本地 socket 或命名管道从别的机器连过来会因为连接被拒绝而挂掉。这个设计初衷是防止别人远程无密码访问是个好设计。如果你确实需要远程连得显式写skip-networkingOFF但说实话重置密码这件事完全可以在本机做没必要开网络。第二个坑是密码策略。8.0 默认装了validate_password组件策略是 MEDIUM要求密码长度至少 8 位并且包含数字、大小写字母和特殊字符。你要是随手设个123456会直接报ERROR 1819 (HY000): Your password does not satisfy the current policy requirements。查一下当前策略SHOW VARIABLES LIKE validate_password%;实在需要设弱密码可以先降低策略级别再改改完再恢复SET GLOBAL validate_password.policy LOW; ALTER USER rootlocalhost IDENTIFIED BY 临时密码; SET GLOBAL validate_password.policy MEDIUM;第三个坑是连接方式。有些环境 TCP 端口不通但 socket 是好的mysql -uroot -h127.0.0.1报错而mysql -uroot -S /var/lib/mysql/mysql.sock秒进遇到连接问题先换 socket 试一下能省下大量排查时间。4. 方案二init-file 一步到位4.1 这个方案的原理和它适合谁--init-file的参数值是某个文件路径服务器启动时会按顺序执行这个文件里的每一条 SQL。既然跳过授权表后各版本都能用ALTER USER改密码那把它提前写进一个文件里启动时自动跑一遍密码就改好了启动完成后服务已经处于正常模式不需要再重启一次。整个过程只需要一次停机操作窗口被压到最短而且脚本可以进版本库、进变更工单审计上说得清楚。这个方案比较适合几个场景生产库要做标准化变更需要记录每一步容器化环境人为交互不方便还有批量场景比如一批测试机要统一改密码。代价是多了一步写文件和设权限的工作但只要按下面的顺序做基本不会出错。4.2 脚本编写与文件权限处理先写脚本文件放在/tmp下内容根据版本调整-- /tmp/mysql-init-password.sql ALTER USER rootlocalhost IDENTIFIED BY Str0ng_Pssw0rd!;如果库里有多个账号要一起处理就往后并列多写几行每条语句都要以分号结尾这是基本要求漏了分号服务器启动会失败。8.0 上如果密码策略过不去可以在第一行先加一句SET GLOBAL validate_password.policy LOW;不过我更建议直接设一个合规的强密码而不是去动策略。文件权限这一步特别容易翻车。MySQL 服务通常以mysql用户身份运行如果脚本文件属主是 root 且权限是 600服务进程读不到文件启动就会失败。用下面这套chown mysql:mysql /tmp/mysql-init-password.sql chmod 0644 /tmp/mysql-init-password.sql0644的含义是任何用户可读、只有属主可写既保证 mysqld 能读到又不会被其他账号随便改。另外脚本里是明文密码改完之后记得立刻shred -u或者rm掉别留在/tmp里过夜。4.3 完整流程与验证把步骤串起来完整走一遍# 1. 停库 systemctl stop mysqld # 2. 备份数据目录强烈建议 tar -czf /backup/mysql_datadir_$(date %F).tar.gz -C /var/lib mysql # 3. 写初始化脚本并设置权限 cat /tmp/mysql-init-password.sql EOF ALTER USER rootlocalhost IDENTIFIED BY Str0ng_Pssw0rd!; EOF chown mysql:mysql /tmp/mysql-init-password.sql chmod 0644 /tmp/mysql-init-password.sql # 4. 带 init-file 启动前台方式方便看日志 sudo -u mysql /usr/sbin/mysqld --init-file/tmp/mysql-init-password.sql --console # 5. 另开一个终端验证 mysql -uroot -p -e SELECT user, host, plugin FROM mysql.user WHERE userroot; # 6. 正常方式重启服务并删除脚本 systemctl start mysqld shred -u /tmp/mysql-init-password.sql第 4 步用前台方式启动是为了能实时看到报错脚本语法有问题会立刻打出来。确认新密码能登进去之后CtrlC停掉前台进程再用systemctl start正常拉起服务。有的人会图省事在配置文件里加init-file...这个做法我不推荐配置文件里的这行一旦忘了删每次启动都会跑一遍脚本虽然结果一样但明文密码就一直留在配置文件旁边了。5. 不同环境下的变体处理5.1 Windows 服务方式安装的 MySQLWindows 上的思路一致只是命令形式不同。先以管理员身份打开命令行停掉服务然后用--console前台启动net stop mysql C:\Program Files\MySQL\MySQL Server 8.0\bin\mysqld.exe --console --skip-grant-tables --shared-memory--shared-memory是为了让客户端能通过共享内存连上因为跳过授权表时网络可能被禁掉本地连接就成了唯一通道。另开一个窗口登录改密码C:\Program Files\MySQL\MySQL Server 8.0\bin\mysql.exe -urootFLUSH PRIVILEGES; ALTER USER rootlocalhost IDENTIFIED BY Str0ng_Pssw0rd!;改完CtrlC停掉前台进程net start mysql重新启动服务用新密码验证。Windows 上有一个额外注意点如果服务是用--defaults-file指定了配置文件前台启动时也要带上同样的参数否则读到的配置不一样可能连不上或者数据目录对不上。5.2 Docker 容器里的 MySQL容器里没有 systemd也没有systemctl可用思路要换成改配置文件再重启容器。第一种方式适合启动时挂载了配置目录的情况直接在宿主机的挂载目录里新增一个配置文件cat /path/to/conf.d/zz-reset.cnf EOF [mysqld] skip-grant-tables EOF docker restart mysql docker exec -it mysql mysql -uroot如果启动时没挂载配置目录可以用docker cp把配置文件拷出来改完再拷回去docker cp mysql:/etc/my.cnf ./my.cnf printf \n[mysqld]\nskip-grant-tables\n ./my.cnf docker cp ./my.cnf mysql:/etc/my.cnf docker restart mysql docker exec -it mysql mysql -uroot如果容器里/etc/my.cnf不存在改成创建/etc/mysql/conf.d/reset.cnf也行官方镜像会加载这个目录。改完密码之后把配置文件里的那行删掉再docker restart mysql恢复。这里有个容易忽略的点容器的ENTRYPOINT每次启动都会执行初始化逻辑如果初始化脚本里有创建用户的语句重启后可能把密码又覆盖回去所以更稳妥的方式是通过环境变量或者初始化 SQL 来管理密码而不是每次手动改。5.3 云托管数据库的账号密码如果你用的是托管型数据库服务本地那套跳过授权表的办法是走不通的因为服务端不开放主机权限你连数据目录都碰不到。这类场景有它自己的重置路径一般是在控制台的实例管理里找到账号管理选中需要重置的账号点重置密码输入新密码并确认。有的平台会要求重置后重启实例才生效有的直接生效。如果控制台没有这个入口就只能提交工单让服务方的技术支持处理。这里顺手提一个容易被混淆的场景服务器操作系统的登录密码忘记和数据库账号密码忘记是两件完全不同的事。前者属于操作系统层面的事处理方式比如进入单用户模式或者通过恢复介质和数据库毫无关系后者才是本文讲的这套逻辑。我遇到过有同学把这两件事搅在一起绕了大半天圈子先分清楚层次再动手。5.4 root 能登只忘了普通账号的密码这种最简单用有权限的账号登录后直接改不需要重启不影响业务ALTER USER app_user% IDENTIFIED BY NewPssw0rd!; FLUSH PRIVILEGES;如果这个账号当前正在被应用使用改完记得同步更新应用侧的连接配置否则应用会开始报连接失败。我建议的操作顺序是先改一个测试账号验证再改生产账号中间留几分钟观察窗口。如果账号很多可以用查询拼出批量语句SELECT CONCAT(ALTER USER , user, , host, IDENTIFIED BY Temp123456;) FROM mysql.user WHERE user NOT IN (root, mysql.sys, mysql.session, mysql.infoschema);跑出来的结果是语句文本确认无误后再复制执行避免误伤系统账号。5.5 MySQL 8.4 与 9.x 的版本变化从 8.4 开始mysql_native_password插件默认不再启用官方把它的开关做成了--mysql-native-passwordON需要显式打开才能用。到了 9.x这个插件被彻底移除新建用户只能用caching_sha2_password或者sha256_password。这对重置密码的影响在于如果你按照老教程写ALTER USER ... IDENTIFIED WITH mysql_native_password BY ...在 8.4 上会直接报插件未加载在新版本上则是未知插件。所以在新版本上重置完密码后如果发现老客户端连不上别急着怀疑密码错了先确认客户端的版本和驱动能力。解决办法有两个要么升级客户端、驱动到支持caching_sha2_password的版本要么在服务端显式启用原生密码插件。前者是长久之道后者只是权宜长期看还是要跟着版本走。5.6 在国产 Linux 发行版上遇到的差异在银河麒麟、统信 UOS 这类基于 Linux 的发行版上部署 MySQL重置密码的流程本身完全一样差异主要体现在几个外围细节上。服务名可能是mysqld也可能是mysql用systemctl list-units | grep -i mysql先确认配置文件路径可能同时在/etc/my.cnf和/etc/mysql/下mysqld --verbose --help | head -30能看到实际的加载顺序按顺序取第一个存在的为准。另一个差异是文件权限和强制访问控制策略。有的系统默认开启了较严格的访问控制mysqld读取/tmp下的脚本文件会被拦表现就是启动失败但错误信息不明显。遇到这种情况把初始化脚本放到数据目录同级的位置比如/var/lib/mysql-files/并把属主设为mysql成功率会高很多。还有一点部分发行版的软件源里 MySQL 和 MariaDB 会互相冲突装之前先rpm -qa | grep -i -E mysql|mariadb清点一下避免出现两个服务抢同一个 socket 的情况。6. 常见报错与排查清单6.1 典型报错速查表处理密码问题的过程中报错信息往往比想象中含糊把常见的几条整理成表出事时对着查能快很多报错信息含义处理方向ERROR 1045 Access denied for user密码错或 host 不匹配确认账号的 host 定义确认密码ERROR 1290 with --skip-grant-tables跳过授权表模式下不能执行该语句先执行FLUSH PRIVILEGESERROR 1819 does not satisfy the policy密码不符合强度策略提高强度或临时降低策略级别ERROR 1130 Host is not allowed客户端来源 IP 不在授权范围检查账号的 host或新建对应 host 的账号ERROR 1820 You must reset your password首次登录需改密码执行ALTER USER ... IDENTIFIED BY ...Plugin caching_sha2_password cannot be loaded客户端不支持新认证插件升级客户端或驱动Cant connect to local MySQL server through socketsocket 路径不对或服务没起检查服务状态和 socket 文件位置mysqld: File /tmp/xxx.sql not found初始化脚本读不到检查路径和文件权限6.2 改完还是登不上按这个顺序排改完密码登不上先别急着重置第二次按这个顺序走一遍基本能定位到问题。第一步确认服务真的起来了systemctl status mysqld看有没有active (running)如果启动失败先去看错误日志通常在数据目录下的.err文件里路径可以在配置文件的log-error项找到。第二步确认用的账号和 host 组合存在SELECT user, host FROM mysql.user;看一眼有没有rootlocalhost这一行有些环境把 root 建成了root%而没有rootlocalhost本机连就会报 1045。第三步确认密码里有没有特殊字符被 shell 吃掉比如$、!、\这些在双引号里会被解释命令行传密码时最好用单引号包住或者干脆不加-p密码这种写法改成交互式输入避免 shell 转义带来的歧义。第四步确认认证插件是否匹配客户端能力用SELECT user, host, plugin FROM mysql.user WHERE userroot;看一眼 plugin 列。第五步如果前面都正常试试换连接方式把-h127.0.0.1换成-S /path/to/mysql.sock或者反过来。6.3 几条踩出来的经验第一条改配置前先确认一遍服务名和配置文件加载顺序我在一台机器上改过三次/etc/my.cnf都没生效最后发现实际加载的是/etc/mysql/mysql.conf.d/mysqld.cnf白折腾半小时。用mysqld --verbose --help的输出确认顺序比凭直觉改文件靠谱。第二条跳过授权表期间把 3306 端口挡掉。我见过因为忘了这一步重置窗口期被人扫到并连上的案例虽然没造成损失但事后复盘时冷汗直冒。防火墙规则临时加一条比事后解释省心。第三条重置完成后一定要用mysql -uroot -p真真切切登一次而不是只看服务状态。有些人改完就继续干别的等到几天后应用要用才发现改错了那时候排查成本完全不同。第四条把整个操作过程写成变更单或者笔记包括改了哪个文件、加了什么参数、备份放在哪。下次再遇到直接照着单子做十分钟结束而不是重新推一遍逻辑。7. 别让忘记密码变成事故后续治理7.1 密码的存储与交接密码忘记绝大多数时候不是技术问题是管理问题。团队里常见的做法是密码存在某个人的便签里、聊天记录里或者某台跳板机的一个文本文件里人一离职就断了线索。我比较推荐的做法是用统一的密码管理工具所有人需要的时候按权限申请查看而不是私下传播。数据库管理员账号的密码尤其应该单独存放不要和应用配置混在一起。如果团队规模不大至少也要做到一件事把数据库管理账号的密码交给一个明确的保管人并在交接文档里写清楚密码存放在哪、由谁负责、紧急情况找谁。这个要求听上去很土但真出事的时候这行字能救几个小时。7.2 账号拆分与最小权限另一个能大幅降低密码问题的做法是把账号拆开。不要所有应用都用 root 连库给每个应用建独立的账号只授予它需要的库和表权限。这样即使某个应用的密码泄露影响面也有限而 root 密码因为使用频次极低反而更容易被记住或者被规范管理。CREATE USER order_app10.0.1.% IDENTIFIED BY App_Pssw0rd!; GRANT SELECT, INSERT, UPDATE, DELETE ON shop.orders TO order_app10.0.1.%; FLUSH PRIVILEGES;顺带补充一句GRANT之后记得确认权限范围SHOW GRANTS FOR order_app10.0.1.%;看一遍别多授了。8.0 之后更推荐用CREATE ROLE定义角色把权限挂在角色上再赋给账号管理上会清晰很多。7.3 把恢复流程真的练一遍最后一条建议有点反常识不要等着出事才第一次做密码重置。在测试环境里照着本文的流程走一遍包括冷备、跳过授权表、init-file、收尾验证全程做下来大概一个小时但你会对自己环境里的服务名、配置路径、日志位置、密码策略全都心里有数。等真出事的时候手上有备份、心里有路径处理起来就是照单执行而不是现场摸索。我在自己维护的几套环境里都备了一份重置操作单放在运维手册里里面写清楚了每台机器的版本、数据目录、服务名和备份路径。这份单子我至今只用过两次但每次用的时候都觉得当初写它花的半个小时太值了。密码忘不忘得掉是运气问题忘掉之后多久能恢复是准备问题。
返回列表