上周帮一位朋友收拾线上数据库的烂摊子,属实有点心疼。他们的MySQL直接把3306端口暴露在公网,root用户密码是6位纯数字,表数据被删了一轮,留下勒索说明。更尴尬的是,检查备份才发现mysqldump从来没成功过,脚本一执行就带着GTID报错中断。这种案例我见过太多了,其实MySQL本身没那么脆,脆的是上线前的加固动作基本没做。
这篇内容我打算把MySQL安全加固拆成十项硬核操作,从账号、权限、网络、传输、审计到备份,把每一项为什么做、怎么做、踩过什么坑一次讲透。适合刚接手公司数据库的运维、被赶鸭子上架的后端开发,以及任何一个准备把MySQL放进生产环境的人。看完照着操作,不能说百分百防住高手,但绝对能把自动扫描脚本和大多数入侵路径挡在门外。
1. 加固前先想清楚的事:哪些地方最容易出问题
1.1 为什么MySQL常常成为攻击目标
MySQL的暴露面其实比很多人想象中大。默认端口3306,默认账号root,默认就允许远程连接,这些“默认”就是攻击者的入场券。互联网上扫端口的脚本几秒钟就能把全网开放3306的IP扫一遍,接下来就是试弱口令、跑漏洞库。一旦进去,第一步通常是查版本、读表结构、找业务数据,然后要么直接拖库,要么加密数据勒索。
更麻烦的是,MySQL的数据文件本身就是明文存储的,拿到文件权限就约等于拿到数据。所以加固的核心思路,是把所有可能被人利用的入口都关掉,把权限和可见性压到最小。这不是某一项配置能做好的,需要从网络到账号再到数据层层设防。
1.2 安全加固不是运维的附加题,而是必答题
我接触过不少团队,数据库上线时赶进度,先把功能跑通,安全的事“以后再说”。以后通常就是出事之后。而且MySQL加固的成本其实很低,大部分操作就是改配置、写SQL、加几条防火墙规则,一两个小时就能完成,但它能把风险大幅降下来。
这篇文章里我会用自己在多个生产环境验证过的方案,按“先封入口、再清账号、再压权限、最后补数据保护”的顺序展开。建议你操作时准备一台测试机,先把每一项跑通,再往生产环境推,不要直接在线上边试边改。
1.3 十大操作全景表
| 操作分类 | 具体操作 | 核心目标 | 风险等级 |
|---|---|---|---|
| 访问控制 | 修改默认端口并限制监听 | 缩小探测面 | 高 |
| 账号安全 | 清理匿名账号及多余账号 | 减少攻击入口 | 高 |
| 密码安全 | 启用密码策略并定期更换 | 防暴力破解 | 高 |
| 权限控制 | 最小权限原则落地 | 降低被拖库后的损失 | 高 |
| 网络防护 | 防火墙IP白名单联动 | 控制来源地址 | 中 |
| 应用层 | 防SQL注入代码规范 | 切断应用层攻击 | 高 |
| 审计追踪 | 开启安全审计与日志 | 提升可追溯性 | 中 |
| 传输安全 | 启用SSL加密连接 | 防监听截获 | 中 |
| 文件安全 | 禁止LOAD_FILE与OUTFILE | 防读写服务器文件 | 高 |
| 数据保障 | 备份与恢复定期演练 | 应对灾难事件 | 高 |
2. 入口与账号控制:先封住外部风险
2.1 修改默认端口并收紧监听地址
MySQL默认3306端口长期被各类扫描工具盯得很紧。我见过很多次攻击日志,扫描器先告警的端口一定是3306,因为默认端口扫到就说明“这是个数据库”。把端口改到非默认位置,能挡住大量无差别扫描。注意这是“降低被扫描概率”,不是绝对安全,所以还要配合其他手段。
操作方式是在my.cnf配置文件的[mysqld]段修改:
[mysqld] port = 3316 bind-address = 127.0.0.1 skip-name-resolvebind-address只监听本机回环地址,意思是外部网络根本访问不到这台MySQL。那应用怎么连?两种情况:应用和MySQL在同一台机器,直接连127.0.0.1没问题;应用在另一台服务器,则不要用bind-address限制本机,而是把bind-address设为应用所在内网网段可访问的IP,再通过防火墙限制来源。
skip-name-resolve这个参数很多人会忽略,它可以让MySQL不反向解析客户端的域名,减少DNS解析超时导致连接变慢的问题,同时也能避免基于主机名的授权被伪造。代价是在授权表里只能使用IP来指定客户端来源。
如果业务已经有很多连接串写着3306,临时没法改端口,那就至少把bind-address设置为内网IP,默认不要监听0.0.0.0。很多生产事故都是所有网卡都在监听,而防火墙规则又漏配导致的。
2.2 清理账号体系,删掉所有不必要账号
装完MySQL后第一件事,是看看系统里都有哪些账号。执行:
SELECT user, host, authentication_string, plugin FROM mysql.user;你会看到只有root和系统自动创建的账号,是正常的。但有时候初始化过程不规范,会留下匿名账号、空密码账号、host为%的root账号,这些都是高危入口。
匿名账号就是用户名为空的记录,例如''@'localhost',任何本地用户都能以匿名身份登录。host为%的root账号意味着root可以从任意IP登录,这是最不能接受的。删除操作:
DROP USER ''@'localhost'; DROP USER 'root'@'%';如果业务确实需要某个账号从多个IP访问,建议按网段拆分账号,而不是直接用%通配。比如应用服务器分布在10.0.1.0/24网段,就创建'app'@'10.0.1.%'。
还有一个容易被忽视的地方:命令行敲mysql -u root -p密码会把密码记到shell历史里。我处理过的很多泄露事件,不是数据库被黑,而是.bash_history被人翻走。密码这类敏感信息应该用mysql_config_editor存储,或者写脚本时用环境变量引用,不要直接出现在命令行里。
2.3 部署密码策略,让弱口令从源头消失
MySQL从5.7开始内置了密码验证插件,8.0里演进为组件。它能在设置或修改密码时强制执行复杂度要求,弱密码直接拒绝。这比事后人工检查靠谱得多。
MySQL 8.0的组件安装方式:
INSTALL COMPONENT 'file://component_validate_password'; SET GLOBAL validate_password.policy = STRONG; SET GLOBAL validate_password.length = 12; SET GLOBAL validate_password.mixed_case_count = 1; SET GLOBAL validate_password.number_count = 1; SET GLOBAL validate_password.special_char_count = 1;5.7版本用插件方式:
INSTALL PLUGIN validate_password SONAME 'validate_password.so'; SET GLOBAL validate_password_policy = STRONG; SET GLOBAL validate_password_length = 12;这些配置要持久化到my.cnf,否则重启就丢了。参数的含义很直白:STRONG策略要求密码长度至少8位,包含大小写字母、数字和特殊字符,并且不能包含用户名等弱密码片段。生产环境建议长度至少12位以上。
密码策略上线时有个坑,就是存量账号密码不符合新策略,但不会被立即强制修改,只有在下次修改密码时才会检查。所以上线策略后,要主动要求所有账号按新标准换一遍密码,包括主从同步账号。
密码到期机制也可以顺手开启。在账号上加上PASSWORD EXPIRE INTERVAL 90 DAY,90天强制换一次。主从账号、监控账号这类服务账号不建议设到期,否则过期会导致复制或监控断开,这个是很多团队踩过的坑。定时改密码后还要注意,改了服务账号密码,应用连接串、主从复制配置都要同步更新,否则会出现改完密码所有服务断连的尴尬局面。
2.4 最小权限原则:每个账号只给够用的权限
最小权限这句话说起来容易,做起来很容易走样。我在生产环境最常见的问题是:开发申请账号,为了方便直接给整个库的ALL PRIVILEGES;读取报表的账号给了INSERT和DELETE权限;甚至有的团队图省事,所有应用共享同一个root账号连接数据库。
正确的做法是按业务角色拆账号。后端应用账号只需要对业务库的增删改查,那就只授这几个权限:
CREATE USER 'app_rw'@'192.168.10.%' IDENTIFIED BY '强密码'; GRANT SELECT, INSERT, UPDATE, DELETE ON appdb.* TO 'app_rw'@'192.168.10.%';只读报表账号不给写权限:
CREATE USER 'app_read'@'192.168.10.%' IDENTIFIED BY '强密码'; GRANT SELECT ON appdb.* TO 'app_read'@'192.168.10.%';如果有定时任务需要执行存储过程,再单独授权EXECUTE。
还有一个关键点:GRANT ALL ON *.*这种权限等于给了一个“管理任意库”的口子,必须严格控制。哪怕只给了一部分库的权限,也要先核对当前账号的实际权限:
SHOW GRANTS FOR 'app_rw'@'192.168.10.%';权限收口后,配合FLUSH PRIVILEGES;让改动生效。但要注意,MySQL 8.0新版的授权基本是自动生效的,不需要手动flush,只有在直接修改mysql.user表时,才需要刷新。平时用GRANT和REVOKE命令改权限即可。
REVOKE回收权限的语法也要吃透,例如收掉某个账号的DELETE权限:
REVOKE DELETE ON appdb.* FROM 'app_rw'@'192.168.10.%';我曾经在一个项目里见过这种情况:账号是'ops'@'%',但运维通过跳板机IP登录,内网审计要求撤销'ops'@'%'的权限,结果直接REVOKE ALL后,发现这个账号下面还有十几个依赖它的自动化脚本在跑。所以做权限回收前,一定要先查清楚这个账号都被谁用了,回收后在低峰期观察告警,确认没问题才算完成。
2.5 防火墙规则配合IP白名单联动
MySQL服务本身做了端口和账号限制还不够,网络层也要拦一道,形成纵深防御。
在Linux上最简单的方式是firewalld。例如只放行应用服务器IP访问3316端口:
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.10.50" port protocol="tcp" port="3316" accept' firewall-cmd --reload如果没有firewalld,用iptables同样能实现:
iptables -A INPUT -p tcp --dport 3316 -s 192.168.10.50 -j ACCEPT iptables -A INPUT -p tcp --dport 3316 -j DROP这里有个常见问题:只配置了当前会话生效的iptables规则,服务器一重启规则全没了。生产环境的iptables必须用iptables-save保存到/etc/sysconfig/iptables,或者用systemd管理规则文件。firewalld相对省心,规则是持久的。
验证规则是否生效,可以在应用服务器上用nc或telnet试一下:
nc -vz 数据库服务器IP 3316能通说明放行正常,在非授权IP上执行同样的命令应该超时或拒绝,这才是符合预期的。我习惯在规则上线前后各抓一次连接测试结果,避免把规则写反导致全公司连不上数据库。
3. 数据与传输安全:把数据本身保护起来
3.1 应用层防SQL注入,数据库侧也要配合
很多运维觉得SQL注入是开发的事,但数据库侧同样能通过账号和权限设计来缓解。拿一个典型的拼接注入来说,Java里如果这样写SQL:
String sql = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";攻击者在username里传入' OR '1'='1,就可能绕过登录。正确做法是使用预编译语句:
PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE username = ? AND password = ?"); ps.setString(1, username); ps.setString(2, password);数据库侧能做的配合是:专门给应用创建读写账号,这个账号对系统表mysql.*没有任何权限,即使应用被注入,攻击者也无法读取数据库的用户名和版本信息。同时禁止使用root作为应用连接账号。
另一个被忽视的注入点是排序字段和表名。预编译语句不能绑定表名和列名,很多方案会选择拼接,这就危险了。稳妥的做法是使用白名单校验:
String orderBy = sortFieldMap.getOrDefault(requestSort, "id");这样即使外部传入任意字符,也只会映射到预设的字段,不会拼进SQL。
数据库账号上还可以顺手做一层限制:假如应用只需要访问appdb,那就只授权appdb。注入攻击一旦进入,能访问的数据范围有限,拖库的成本会大幅提高。
3.2 打开审计日志,让攻击和数据泄漏有迹可循
没有审计的数据库就是一座黑屋,出事了根本不知道谁进来过、干了什么。MySQL的general_log会记录所有客户端请求,包括登录失败记录和执行的SQL,是排查问题的神器。但开启它会带来性能损耗和磁盘占用,所以我的建议是:
在需要排查问题时临时开启,用完立刻关闭:
SET GLOBAL general_log = ON; -- 等待一段时间收集信息 SET GLOBAL general_log = OFF;长期审计,有条件的团队建议上企业版审计插件,或者用MariaDB的server_audit插件。社区版MySQL没有原生的高级审计插件,可以自己做个轻量方案:利用init_connect在每次连接建立时,向审计表写入登录信息。
先建审计表:
CREATE DATABASE IF NOT EXISTS auditdb; CREATE TABLE auditdb.access_log ( id INT PRIMARY KEY AUTO_INCREMENT, login_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, user VARCHAR(64), host VARCHAR(128) );然后给所有需要登录数据库的普通账号,授权对这张表的INSERT权限,并把init_connect配置到my.cnf:
[mysqld] init_connect='INSERT INTO auditdb.access_log(user, host) VALUES (CURRENT_USER(), CURRENT_USER());'CURRENT_USER()返回的是账号@来源IP,能准确记录谁在什么时候连过。但要注意,拥有SUPER或CONNECTION_ADMIN权限的账号不会执行init_connect,这是MySQL的自我保护机制,so root账号不会被记录到这个表里。所以这只适合记录普通业务账号,root的访问还是靠general_log和系统审计来补,这也是为什么业务账号千万别用root的原因之一。
日志这块还要做好轮转。MySQL原生的binlog和错误日志会不断增长,一般通过logrotate或者mysqld_safe自带的日志轮转机制来切割。但general_log没有原生轮转,必须自行处理,否则一路跑下去能把磁盘直接撑爆。处理方式通常是定期调用mysqldump导出或拷贝后truncate,配合crontab实现。
3.3 启用SSL加密,防止连接被监听抓包
MySQL客户端和服务器之间的通信,默认是明文传输的。如果你的数据库和应用服务器不在同一台机器,跨机房甚至跨地域连接时,数据包在线路上是完全裸露的。还有更现实的问题,我见过某公司内部机房的镜像端口被人接了一台抓包机,能直接看到所有数据库账号密码。SSL可以阻断这一类中间人攻击。
检查当前是否支持SSL:
SHOW VARIABLES LIKE 'have_ssl';如果是DISABLED或NO,需要配置证书。自己用openssl生成一套测试用的自签证书:
openssl req -newkey rsa:2048 -nodes -keyout ca-key.pem -x509 -days 3650 -out ca.pem openssl req -newkey rsa:2048 -nodes -keyout server-key.pem -out server-req.pem openssl x509 -req -in server-req.pem -days 3650 -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem以实际配置到my.cnf:
[mysqld] ssl-ca=/etc/mysql/ssl/ca.pem ssl-cert=/etc/mysql/ssl/server-cert.pem ssl-key=/etc/mysql/ssl/server-key.pem require_secure_transport = ONrequire_secure_transport = ON的意思是强制所有连接都走SSL加密。设置前要确保应用连接串和客户端能支持SSL,否则会出现全部连接被拒的生产事故。
MySQL账号也可以单独指定必须使用SSL:
CREATE USER 'secure_app'@'192.168.10.%' IDENTIFIED BY '强密码' REQUIRE SSL;这个操作的坑在于:Java的JDBC连接串、Python的PyMySQL、PHP的mysqli,每个语言都需要额外配置证书信任或开启SSL参数。比如JDBC要加?useSSL=true&verifyServerCertificate=false。很多团队改完SSL才发现驱动不兼容,所以上线前务必用真实的开发环境连接串跑一遍冒烟测试。
3.4 限制文件读写,把SQL注入的杀伤力降到最低
MySQL的LOAD DATA INFILE和SELECT ... INTO OUTFILE功能非常危险。攻击者一旦拿到写权限,配合SQL注入漏洞,可以把恶意代码写入web目录,或者读取服务器本地的敏感文件。这类攻击最常见的形式是先通过SQL注入拿一点权限,再调用LOAD_FILE('/etc/passwd')读文件,甚至用INTO OUTFILE写webshell。
加固方法是在my.cnf里限制:
[mysqld] secure_file_priv = /var/lib/mysql-files local_infile = 0secure_file_priv指定一个目录,只有这个目录允许LOAD_FILE和INTO OUTFILE操作,其他任何路径都被拒绝。如果业务根本不需要文件导入导出,可以设置为空字符串禁用全部。local_infile = 0则彻底禁止客户端执行LOAD DATA LOCAL INFILE。
这个配置不会影响常规的SELECT、INSERT操作,对正常业务基本透明。但它能保证即使应用层被SQL注入突破了,攻击者也很难把数据库当成跳板去读写服务器文件。很多朋友会忽略这个配置,我觉得它是性价比极高的一个加固项。
备份和批量导入如果确实需要文件操作,可以先手动把文件放到/var/lib/mysql-files目录,再执行导入,流程上多一步,但安全性和规范性都提升了。
3.5 备份恢复与灾难演练,关键时刻能救命
安全加固不只是防入侵,还要防数据丢失。我们做一整套加固动作后,备份就是最后一道保险。很多团队有备份,但从来没演练过恢复,等到真需要恢复时,才发现脚本一直报错或者备份文件损坏,那才是真正的灾难。
生产环境我习惯搭配两类备份:逻辑备份和binlog增量备份。逻辑备份用mysqldump,每周全量一次:
mysqldump --single-transaction --routines --triggers --events --master-data=2 -u备份账号 -p appdb > appdb_$(date +%F).sql--single-transaction对InnoDB表做一致性快照,不会锁表,这个参数在生产环境必须加。--master-data=2会在备份文件里记录binlog位置,方便做时间点恢复。--routines --triggers --events是导存储过程、触发器、事件,很多人的备份漏了这些,恢复后应用一调用存储过程就报错。
主从复制的环境还要注意一个事:如果开了GTID,mysqldump备份出来的文件默认会带SET @@GLOBAL.GTID_PURGED语句,在MySQL 5.7和8.0的某些场景下,恢复时如果服务器GTID状态不一致,会直接报错。批量执行恢复时可能需要加--set-gtid-purged=OFF,先把数据导进去,再重建复制关系。
binlog增量恢复是一个必备技能。比如每天凌晨全量备份,今天上午10点误删了一张表,恢复流程就是先恢复昨天的全量备份,再重放从昨天备份点到10点的binlog:
mysqlbinlog --start-datetime="2025-01-20 03:00:00" --stop-datetime="2025-01-20 10:00:00" mysql-bin.000015 | mysql -u root -p操作时务必确认binlog时间段内的日志还在,不要等到误删了才想起来binlog过期被清理了。binlog过期时间建议至少覆盖两个全量备份周期,我给生产环境的推荐是expire_logs_days设置7天以上,同时保证每天都有全量备份,这样任何一天内的数据丢失都能找回。
备份文件本身也要加密存储,并定期测试恢复。我每个月会在测试环境完整恢复一次线上备份,验证备份文件可用性和恢复流程是否顺畅。这个习惯在关键时刻真的能救命。
4. 加固落地中的高频问题与排查技巧
4.1 问题速查表
| 问题现象 | 可能原因 | 排查与解决 |
|---|---|---|
| 修改端口后应用连不上 | 防火墙未放行新端口 | 检查firewalld/iptables规则,确认SELinux是否拦截 |
| 开启SSL后连接失败 | 驱动不支持或证书配置错误 | 确认JDBC/客户端SSL参数,用mysql命令行验证 |
| 密码策略开启后无法修改密码 | 新密码不符合复杂度要求 | 临时调整策略参数,或用符合要求的强密码 |
| 授权后不生效 | 直接改了mysql.user表未刷新 | 使用GRANT语法,FLUSH PRIVILEGES |
| FLUSH PRIVILEGES执行卡住 | 存在长时间事务或大查询 | 等待执行结束,或分析慢查询后断开长事务 |
| 执行mysqldump报GTID错误 | 恢复库已有GTID执行记录 | 加--set-gtid-purged=OFF或用新恢复环境 |
| secure_file_priv生效后LOAD DATA报错 | 文件不在允许目录 | 将文件放到指定目录或调整secure_file_priv配置 |
| 修改bind-address后主从不同步 | 主库或从库无法互相连接 | 检查允许从库IP访问主库的账号和防火墙 |
| validate_password组件安装失败 | 插件文件缺失或配置文件冲突 | 检查plugin_dir路径,确认文件是否可读 |
| 审计表疯狂增大 | 连接太频繁且无清理任务 | 定期清理历史,按天分区审计表 |
4.2 改端口后连接不上的问题,百分之八十是防火墙和SELinux
有一次帮客户做加固,my.cnf改完端口重启MySQL后,本地连接正常,应用服务器死活连不上。排查了一圈,发现firewalld还放行着3306,新端口3316根本不通。更隐蔽的是SELinux,MySQL默认只放行3306端口,换端口后即使防火墙放行了,SELinux也会拦住。
处理方式两种,要么调整SELinux策略:
semanage port -a -t mysqld_port_t -p tcp 3316要么干脆为这台数据库服务器在安全的网络环境里关闭SELinux,但我不建议这么干,能保留还是保留。在改端口之前就把这些网络层的拦截点都检查一遍,能省很多现场排查的时间。
4.3 密码策略导致的连锁问题
上线密码策略后的头几天,最容易出的问题就是定时任务和应用连接密码不符合复杂度要求,导致连接失败。这里有个细节:validate_password只影响修改密码时的强度校验,不会强制已经被创建出来的弱密码失效。所以上线策略前,需要列一份现有账号清单,逐个确认是否为强密码,不符合的主动更换。
另一个坑是主从复制。MySQL复制账号的密码如果不符合新策略,改密后得同时更新主从配置中的复制密码,特别是使用CHANGE MASTER TO配置的从库,只改数据库账号密码而不更新连接配置,从库就会一直报认证错误。这个在排查时经常被忽略。
4.4 审计日志开启后磁盘爆满
general_log是请求级别的日志,写入量极大。我曾经在压测环境开过一次,一夜之间产生了几百GB的日志文件,把磁盘直接写满,业务全部卡死。现在我的习惯是,general_log只作为临时诊断工具,开之前先确定日志路径,并在同一条命令里安排自动关闭的定时任务。
更平滑的方案是把general_log输出到一张表而不是文件:
SET GLOBAL log_output = 'TABLE'; SET GLOBAL general_log = ON;这样查询日志可以直接SELECT mysql.general_log,排查完立刻关闭,但要注意这张表同样会膨胀,需要定时做归档和清理。
5. 加固后的自检清单,以及我的一些习惯
5.1 用这几条SQL给MySQL做个体检
加固是不是做完了,不能靠感觉,得用命令验证。我每次操作完都会跑一遍自检SQL,确认关键项符合预期:
SHOW VARIABLES LIKE 'port'; SHOW VARIABLES LIKE 'bind-address'; SHOW VARIABLES LIKE 'have_ssl'; SHOW VARIABLES LIKE 'require_secure_transport'; SHOW VARIABLES LIKE 'validate_password%'; SHOW VARIABLES LIKE 'secure_file_priv'; SHOW VARIABLES LIKE 'local_infile'; SELECT user, host, authentication_string FROM mysql.user WHERE authentication_string = ''; SELECT user, host FROM mysql.user WHERE host = '%'; SHOW GRANTS FOR 'app_rw'@'192.168.10.%';空密码账号和%主机账号是重点关注对象,只要自检结果里有任何一项异常,都不要放过。这两条SQL执行很快,完全可以做成一个定时巡检脚本,每周把异常结果发到运维群。
5.2 账号权限的周期性复查
数据库的管理账号会随着人员变动越积越多。一个人离职后,他的数据库账号可能还留在系统里,成了潜伏期后门。我建议每个季度做一次账号权限全员复查:导出所有账号和权限,逐个确认负责人、用途、最近登录时间。
一条实用的查询,可以看每个账号最近登录时间:
SELECT user, host, MAX(login_time) FROM auditdb.access_log GROUP BY user, host;没有登录记录的账号,要么是监控账号,要么是已经废弃的账号,逐个确认后回收。这个动作不仅提高了安全性,也让权限清单始终处于可控状态。
5.3 别忽略版本升级,安全加固的动态性
安全是动态的,不是配置一遍就永久有效。MySQL官方每个季度都会发布安全更新版本,修复已知漏洞。配置上做得再好,版本严重滞后等于给攻击者留了后门。我的建议是订阅官方发布公告,大版本尽量跟随,小版本至少保持在一个可接受的范围。
版本升级同样要先在测试环境验证,重点观察应用兼容性和复制链路状态。特别是MySQL 5.7到8.0的升级,认证插件默认从mysql_native_password变为caching_sha2_password,老版本客户端可能连不上,这个是升级队最常踩的雷。
5.4 说点实在的个人体会
做了这么多年数据库相关的维护,我越来越觉得:安全加固不是一堆命令的堆砌,而是从第一天规划架构时就该考虑的事。很多时候我们总是被业务追着跑,上线优先、安全靠后,等真的出事了才手忙脚乱。但一次被拖库、一次误删数据,代价远高于一开始就做对的成本。
如果让我给刚起步的团队一个务实的路线:先完成这十大操作里的端口改造、账号瘦身、密码策略、最小权限、备份恢复这五项,它们能在较短时间把风险降下一大截。剩下的SSL、审计、文件读写限制,可以在业务稳定的窗口期逐步推进。每做完一项,更新对应的文档和监控,让整个加固过程可以追溯。数据库这条路,谨慎和细心永远不亏。