等保测评现场,MySQL数据库几乎是绕不开的检查对象。很多刚开始做等保的朋友会问:数据库到底怎么测?其实把等保要求落到具体命令上,事情就清晰了一半。这篇文章我会按身份鉴别、访问控制、安全审计、数据完整性与备份恢复这几个维度,把我在测评MySQL时常用的等保测评命令逐条列出来,每条命令都说明查什么、结果怎么判、整改怎么改。测评机构的技术人员、甲方DBA、做等保整改的工程师,甚至正在用MySQL做课程设计或练习的人,都可以把这套命令当成一份检查手册来用。
1. 等保测评MySQL的整体思路与检查项拆解
1.1 等保测评到底查MySQL的哪些内容
等保2.0标准对数据库的要求分散在多个控制项里,不能一上来就乱敲命令。我习惯先把它归纳成五个方向:
第一是身份鉴别。数据库的登录账号、口令复杂度、口令有效期、登录失败处理,都属于这一类。对应MySQL就是用户表、密码策略插件、登录失败控制插件。
第二是访问控制。查用户的权限分配、是否存在空口令账号、高危权限、远程访问host,以及账号是否按“最小权限”原则隔离。
第三是安全审计。查数据库有没有把登录和增删改查行为记录下来,日志留存是否足够,binlog是否开启,审计插件是否存在。
第四是入侵防范。数据库版本是否过旧、是否被暴露在公网端口、是否安装了不必要的组件、是否还有默认弱口令。
第五是数据完整性和备份恢复。数据校验逻辑是否开启、事务刷盘策略是否安全、binlog是否完整、备份任务和恢复演练是否有实际记录。
这里有一条容易踩的坑:只靠数据库命令行看运行参数是不够的,还需要读配置文件。因为像general_log这种参数,可以运行时临时打开,但一旦重启就失效;如果配置文件里没有持久化,等保测评时只能算“部分符合”,甚至算不符合。所以整体思路是“配置文件 + 运行参数 + 日志文件”三样对照着看。
1.2 检查项与SQL命令的映射关系
把检查项和SQL命令对应起来,上手会快很多。下面这张表是我经常用的映射关系:
| 等保控制点 | 核心检查点 | 关键命令 | 判断依据 |
|---|---|---|---|
| 身份鉴别 | 口令复杂度、有效期、失败处理 | SHOW VARIABLES LIKE 'validate_password%'; SHOW VARIABLES LIKE 'connection_control%'; | 是否安装策略组件,密码复杂度是否达到要求 |
| 访问控制 | 用户清单、权限、空口令、远程host | SELECT user,host FROM mysql.user; SHOW GRANTS FOR '用户'@'host'; | 是否存在匿名账号、空口令、权限过大 |
| 安全审计 | 审计日志、binlog、错误日志 | SHOW VARIABLES LIKE 'general_log%'; SHOW VARIABLES LIKE 'log_bin%'; | 日志是否开启、是否长期留存 |
| 入侵防范 | 版本、端口、漏洞补丁 | SELECT VERSION(); SHOW VARIABLES LIKE 'port'; | 版本是否过旧、端口是否不必要暴露 |
| 数据完整性 | 数据校验、刷盘策略、传输加密 | SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit%'; SHOW VARIABLES LIKE 'have_ssl%'; | 数据写入是否安全、管理通道是否加密 |
| 备份恢复 | binlog状态、备份文件、恢复演练 | SHOW BINARY LOGS; SHOW MASTER STATUS; | binlog是否连续、有无全备和恢复记录 |
这个映射不是死板的标准,而是我从实际测评中总结出来的。不同项目用的安全策略不同,命令可能需要增删,但大方向逃不出这几类。
1.3 我习惯的检查顺序:配置文件、运行参数、日志三件套
现场检查时,我一般按三步走:
第一步,先看my.cnf。找到MySQL实例的配置文件,重点看[mysqld]段的参数,比如validate_password、log-bin、server-id、general_log、expire_logs_days等。有些客户用的是Linux离线安装的MySQL,配置文件路径不一定在/etc/my.cnf,可能是/etc/mysql/my.cnf或者安装目录下的my.cnf,需要先确认。
第二步,登录MySQL执行只读查询。用SELECT VERSION()确认版本,再按1.2里的命令逐项查运行参数。这里要注意MySQL 5.7和8.0的差异,很多变量名不一样,后面会详细说。
第三步,看日志文件。去数据目录下查看binlog文件、错误日志、慢查询日志是否真实存在,是否按天切割,是否有人定期归档。有些库虽然参数显示开启,但日志文件早被手动删了,这种情况在等保上属于“未有效留存”,照样扣分。
2. 四大核心检查维度的命令细节与判定逻辑
2.1 身份鉴别:口令复杂度、登录失败与账号密码存储
身份鉴别里最容易出问题的就是口令策略没有启用。MySQL官方自带的密码策略在5.7里是插件validate_password,在8.0里变成了组件validate_password。先执行:
SHOW VARIABLES LIKE 'validate_password%';如果返回Empty set,说明密码策略根本没有安装,这种情况可以直接判为不符合。如果能看到validate_password_length=8、validate_password_policy=MEDIUM、validate_password_mixed_case_count=1、validate_password_number_count=1、validate_password_special_char_count=1,基本可以判定满足“密码复杂度”的要求。
8.0安装组件的命令是:
INSTALL COMPONENT 'file://component_validate_password';5.7安装插件的命令是:
INSTALL PLUGIN validate_password SONAME 'validate_password.so';这里有个细节:8.0安装后参数名中间的连接符是点,比如validate_password.policy;5.7是下划线,比如validate_password_policy。查询时用LIKE 'validate_password%'都能匹配到,但手工翻配置时要分清版本。
再看登录失败处理。MySQL本身没有像某些商业数据库那样直接配置“失败次数锁定”,通常用connection_control插件实现。执行:
SHOW VARIABLES LIKE 'connection_control%';如果结果为空,说明登录失败处理没有做。这个插件的思路不是锁定账号,而是让连续失败的登录请求延迟响应,从而拖慢暴力破解。整改时安装CONNECTION_CONTROL和CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS两个插件,再设置阈值即可。
账号密码存储方式也要看。执行:
SELECT user, host, plugin, authentication_string FROM mysql.user;8.0默认caching_sha2_password,5.7常见mysql_native_password。等保测评不会强制要求用某个具体插件,但会关注两点:一是口令不能明文存储,二是尽量使用不可逆哈希算法。如果还在用mysql_native_password这种旧插件,且版本是8.0,建议迁移到caching_sha2_password。
2.2 访问控制:用户权限、空口令与远程访问风险
访问控制是等保测评里发现问题最多的地方。第一个动作是拉全量账号:
SELECT user, host, plugin FROM mysql.user;重点看有没有匿名账号,比如user字段为空的那种。匿名账号加上宽松host,基本可以直接判定不符合。接着查空口令:
SELECT user, host FROM mysql.user WHERE authentication_string='';有查询结果就是高风险。很多老系统都会残留这种垃圾账号,整改就是删掉它们。
权限过大也很常见。我一般直接查用户表中几个高危权限标志位:
SELECT user, host, grant_priv, super_priv, file_priv, process_priv FROM mysql.user;SUPER权限可以绕过很多限制,FILE权限能读写数据库服务器上的文件,PROCESS权限能查看当前所有会话。业务账号如果有这些权限,属于明显越权。再配合:
SHOW GRANTS FOR '业务账号'@'host';确认某个账号实际能操作的范围。测评中经常见到GRANT ALL PRIVILEGES ON *.* TO 'app'@'%',这种写法把库表所有权限全给了应用账号,也不限定来源IP,风险等级很高。
远程访问方面,执行:
SELECT user, host FROM mysql.user WHERE host NOT IN ('localhost', '127.0.0.1', '::1');凡是host为%的账号,都在提示“这台数据库允许任意IP连接”。有些业务确实需要远程连接,但应该把host限制到具体的应用服务器网段,而不是放任全网。
2.3 安全审计:通用日志、binlog与审计插件的取舍
MySQL的审计能力分好几个层次。最基础的是通用日志、慢查询日志、错误日志和binlog。检查命令如下:
SHOW VARIABLES LIKE 'general_log%'; SHOW VARIABLES LIKE 'slow_query_log%'; SHOW VARIABLES LIKE 'log_bin%'; SHOW VARIABLES LIKE 'log_error%';等保测评看的是“关键操作是否有记录”。如果开了binlog,增删改操作都能从binlog里还原,这是最可靠的审计依据之一。所以log_bin最好是ON,且binlog_format建议为ROW,因为ROW格式记录了每一行数据的变化,比STATEMENT格式更完整。
通用日志general_log会记录所有连接和SQL语句,审计效果很强,但在生产环境会带来非常大的磁盘I/O压力。我见过客户为应付等保把general_log开起来,结果一天写了上百GB日志,业务直接卡死。所以我不建议无脑开general_log,更合适的做法是评估业务容忍度,选择审计插件、开启binlog加应用层审计,或者用专门的数据库审计系统。
第三方审计插件方面,执行:
SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE '%audit%';能查到audit_log就是装了商业审计插件,查不到不代表没有审计,可能用的是binlog或外部日志采集。测评判定时要结合整个审计方案看,不能因为一个插件名缺失就一票否决。
2.4 数据完整性与备份恢复:校验算法、binlog与恢复验证
数据完整性在等保里容易被忽略。MySQL层面主要看几个参数:
SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit%'; SHOW VARIABLES LIKE 'sync_binlog%'; SHOW VARIABLES LIKE 'innodb_checksum_algorithm%';innodb_flush_log_at_trx_commit=1表示每次事务提交都刷盘,最安全但性能最差;如果值是0或2,崩溃时可能丢数据。sync_binlog=1同理。等保测评看到非1的配置,通常会咨询业务是否接受数据丢失窗口。
备份恢复方面,先确认binlog是否开启且连续:
SHOW MASTER STATUS; SHOW BINARY LOGS;接着看binlog保留时长。MySQL 5.7用expire_logs_days,8.0用binlog_expire_logs_seconds:
SHOW VARIABLES LIKE 'expire_logs_days%'; SHOW VARIABLES LIKE 'binlog_expire_logs_seconds%';只开了binlog但没有保留足够天数,备份恢复环节照样过不了。更关键的是恢复演练,不能只看服务器上有没有备份文件。我会要求客户在测试环境执行一次真实恢复,比如:
mysql -uroot -p 业务库 < /backup/业务库_20250101.sql然后再用binlog做增量恢复:
mysqlbinlog --start-datetime="2025-01-01 12:00:00" --stop-datetime="2025-01-01 13:00:00" /data/mysql/mysql-bin.000012 | mysql -uroot -p能恢复到指定时刻的数据,才叫“备份可用”。很多库只做了dump却没做恢复演练,测评时会被记录为“备份恢复机制不完整”。
3. 动手实操:一套可直接复用的等保检查命令清单
3.1 连接数据库的正确姿势和现场环境准备
到现场先别急着动手,先确认几件事:
- 数据库版本:
SELECT VERSION(); - 配置文件路径:
SHOW VARIABLES LIKE 'basedir'; SHOW VARIABLES LIKE 'datadir'; - 当前端口:
SHOW VARIABLES LIKE 'port'; - 当前主机名和实例名:
SHOW VARIABLES LIKE 'hostname';
连接时不要用业务账号执行高权限操作,测评过程以只读查询为主。能用SELECT和SHOW解决,就绝不碰UPDATE、DELETE、GRANT。如果环境不允许远程连接,就直接在服务器本地通过socket登录:
mysql -uroot -p --socket=/tmp/mysql.sock如果服务器上MySQL是容器化部署,需要先确认socket映射路径,再调整参数。
3.2 核心命令速查表
下面这组命令是我在多个测评项目中整理出来的精简版,可以直接复制到终端执行。它会输出所有关键信息到一个日志文件,方便留存证据:
mysql -uroot -p -h127.0.0.1 --tee=/tmp/mysql_等保检查_$(date +%Y%m%d).log <<'EOF' SELECT VERSION(); SHOW VARIABLES LIKE 'port'; SHOW VARIABLES LIKE 'validate_password%'; SHOW VARIABLES LIKE 'default_password_lifetime%'; SHOW VARIABLES LIKE 'connection_control%'; SELECT user, host, plugin, authentication_string FROM mysql.user; SELECT user, host, grant_priv, super_priv, file_priv, process_priv FROM mysql.user; SHOW VARIABLES LIKE 'general_log%'; SHOW VARIABLES LIKE 'slow_query_log%'; SHOW VARIABLES LIKE 'log_bin%'; SHOW VARIABLES LIKE 'binlog_format%'; SHOW BINARY LOGS; SHOW MASTER STATUS; SHOW VARIABLES LIKE 'expire_logs_days%'; SHOW VARIABLES LIKE 'binlog_expire_logs_seconds%'; SHOW VARIABLES LIKE 'log_error%'; SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit%'; SHOW VARIABLES LIKE 'sync_binlog%'; SHOW VARIABLES LIKE 'have_ssl%'; SHOW VARIABLES LIKE 'require_secure_transport%'; SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE '%audit%'; EOF执行完以后,重点看下面几个返回值:
| 命令/返回内容 | 判定逻辑 |
|---|---|
validate_password_length=8及以上 | 密码长度基本满足 |
validate_password_policy或validate_password.policy为 MEDIUM/STRONG | 密码复杂度策略启用 |
connection_control_failed_connections_threshold大于0 | 登录失败处理已配置 |
mysql.user中空口令、匿名账号数量 | 存在即不符合 |
mysql.user中host='%'且来自业务网段外 | 远程访问控制需整改 |
app账号具有SUPER或FILE权限 | 权限过大 |
general_log、log_bin、log_error均为ON | 审计基本条件具备 |
binlog_format=ROW | 审计数据更完整 |
binlog_expire_logs_seconds或expire_logs_days满足留存要求 | 留存周期充足 |
innodb_flush_log_at_trx_commit=1 | 数据完整性最强 |
have_ssl=YES、require_secure_transport=ON | 传输通道加密 |
3.3 现场证据的收集与记录规范
测评最怕“口说无凭”。我执行命令时会把输出完整保存下来,最好带时间戳。MySQL的--tee参数可以直接把所有命令回显写到文件里,这是最省事的做法。
tee日志只能记录当前会话,如果想单独执行某条命令并保存,也可以用:
mysql -uroot -p -e "SELECT user,host FROM mysql.user;" > /tmp/mysql_user_check.txt注意不要在命令行里直接写数据库口令,等保测评本身就是查安全,命令行明文口令会成为新的风险点。-p后面不带参数,让MySQL交互式提示输入即可。
截图证据也要带主机名和时间。Linux下可以先用hostname命令打印主机名,再执行MySQL命令。这样后续评审时,证据对应的实例是谁、查的是什么时间点,一目了然。
4. 常见问题、排查技巧与开发场景延伸
4.1 MySQL 5.7与8.0命令差异导致查询结果为空
最常见的问题是:SHOW VARIABLES LIKE 'validate_password%'查出来是Empty set。不同版本的解决方案完全不同。
5.7需要用INSTALL PLUGIN validate_password SONAME 'validate_password.so'先装插件,装完再配置validate_password_policy等参数。8.0需要用INSTALL COMPONENT 'file://component_validate_password'安装组件,配置参数名也要改成点号风格。
另一个例子是binlog过期时间:
| 版本 | 查询命令 | 设置参数 |
|---|---|---|
| MySQL 5.7 | SHOW VARIABLES LIKE 'expire_logs_days%' | expire_logs_days=30 |
| MySQL 8.0 | SHOW VARIABLES LIKE 'binlog_expire_logs_seconds%' | binlog_expire_logs_seconds=2592000 |
如果拿着5.7的命令去测8.0,会得到空结果,但这不代表没有这个功能,只是参数名变了。测评人员必须先在现场确认版本,再决定命令集。
主从状态命令也要分版本。8.0.22之前是SHOW SLAVE STATUS\G,之后是SHOW REPLICA STATUS\G。如果主从检查时用了旧命令,新版本可能会提示语法变化,甚至查不到状态。
4.2 权限不足时如何完成检查
等保测评不总是能拿到root账号。有些生产库禁止使用高权限账号,只给一个只读账号。这时mysql.user表可能查不到,因为mysql.user本身需要SELECT权限,且权限管理严格时只读账号不允许直接读系统表。
我的处理方式是让DBA协助执行命令,并把结果直接输出给测评方。这不影响测评结论是否客观,关键是拿到真实数据。如果连DBA都不能配合,那就只能通过SHOW GRANTS FOR CURRENT_USER();先确认当前账号能看到哪些信息,再在有限范围内做检查,然后把“信息收集受限”写进记录。
有些场景下可以通过INFORMATION_SCHEMA视图替代。比如:
SELECT * FROM INFORMATION_SCHEMA.USER_PRIVILEGES;但它的粒度不如mysql.user细,只能作为辅助证据。
4.3 只读库、离线环境下的检查方法
遇到过很多次,数据库是只读副本,或者服务器在内网离线环境,无法直接安装插件、无法访问外部工具。这种环境里,动态参数也要谨慎设置。
在只读实例上,SET GLOBAL通常没有权限,即使有权限,也只是临时生效,重启后会丢。唯一的办法是改配置文件并安排重启窗口。如果业务不能停,就要先记录“当前不符合”,再走变更流程整改。
Linux上离线安装MySQL的场景也很常见。离线环境下没有外部软件源,安装插件时可能缺依赖,比如validate_password组件需要的库文件不存在。这时先检查MySQL安装包完整性和自带组件文件,再手动拷贝到plugin_dir目录。测评时如果发现审计插件未安装,不能简单说“装不了”,而是要给出一套可落地的离线整改方案。
4.4 连接池、QT读取结构与结构修改在等保里的实际影响
开发同学经常遇到几类问题,也会在等保测评时被暴露出来。
第一类是数据库连接池配置。Java应用开发中常用的连接池有Druid、HikariCP等,它们会保持很多长连接。等保测评时我遇到过一次,应用反馈数据库连不上,一查max_connections只有200,而连接池最大连接数直接配到300,连接池把数据库连接耗尽。虽然等保测评不直接检查连接池参数,但会通过SHOW PROCESSLIST看到大量Sleep会话,这也是会话安全管理不到位的表现。整改建议是调低连接池最大连接数、设置空闲超时时间,并限制连接池账号的来源IP。
第二类是管理工具直连数据库结构。很多项目会用QT、Navicat、DBeaver等工具读取MySQL数据库结构,本质是查INFORMATION_SCHEMA.TABLES和INFORMATION_SCHEMA.COLUMNS。这些工具一旦允许远程连接,且账号没有限制host,就会成为暴力破解和撞库的目标。等保测评时,我会重点检查这些管理工具账号是否开启了SSL通道、是否只能从运维网段登录。
第三类是结构修改和唯一索引问题。开发中经常要给表加字段、加唯一索引:
ALTER TABLE user ADD COLUMN phone VARCHAR(20); ALTER TABLE user ADD UNIQUE KEY uk_phone (phone);如果表里已经有重复的phone值,第二步会直接报错。很多开发同学会问“mysql设置唯一已经有重复数据库”,这时候只能先清理或合并重复数据,再加唯一索引。等保测评关注的不只是最终结构,还有变更流程是否留痕。结构修改属于影响数据库可用性的操作,至少要能查到变更记录,不能绕过审批直接在生产库执行。
5. 从等保测评反推MySQL加固配置参考
5.1 口令策略与登录失败处理的落地配置
整改时,我一般会给出可复用的配置段。5.7环境在my.cnf的[mysqld]下增加:
plugin-load-add=validate_password.so validate_password_policy=MEDIUM validate_password_length=8 validate_password_mixed_case_count=1 validate_password_number_count=1 validate_password_special_char_count=1 default_password_lifetime=908.0环境先执行组件安装,再在my.cnf里配置:
validate_password.policy=MEDIUM validate_password.length=8 validate_password.mixed_case_count=1 validate_password.number_count=1 validate_password.special_char_count=1 default_password_lifetime=90 connection_control_enabled=ON connection_control_failed_connections_threshold=5 connection_control_min_connection_delay=1000配置完成后用SHOW VARIABLES LIKE 'validate_password%'和SHOW VARIABLES LIKE 'connection_control%'复查。注意动态设置和持久化是两回事,只有写入配置文件并重启后才是持久化生效。
账号本身也要改。普通应用账号尽量用强密码,不要用root连库。创建账号时指定密码加密方式和主机范围:
CREATE USER 'app'@'10.0.0.%' IDENTIFIED WITH caching_sha2_password BY 'Str@ngP@ssw0rd';5.2 最小权限和访问来源限制的配置实例
业务账号只给业务库的增删改查权限,不给管理权限。比如:
GRANT SELECT, INSERT, UPDATE, DELETE ON appdb.* TO 'app'@'10.0.0.%';不要去执行GRANT ALL ON *.*。如果原先的账号权限过大,先回收:
REVOKE SUPER, FILE, PROCESS, GRANT OPTION ON *.* FROM 'app'@'%';如果账号的host写的是%,尽量改成具体应用服务器IP或网段:
ALTER USER 'app'@'%' TO 'app'@'10.0.0.%';这一步看着简单,实际很折腾,因为应用连接串也要跟着改。所以在测评整改方案里,我会把“账号host变更”和“应用发布窗口”放在一起安排,避免线上改完连不上。
空口令和匿名账号直接清理:
DROP USER ''@'localhost'; DROP USER ''@'%'; -- 具体host按实际查询结果5.3 日志、binlog与备份恢复的推荐配置
审计和备份是等保测评的重头戏。推荐的生产配置如下:
[mysqld] log-bin=mysql-bin server-id=1 binlog_format=ROW expire_logs_days=30 # MySQL 8.0 使用下面这行,与上面二选一 # binlog_expire_logs_seconds=2592000 log_error=error.log slow_query_log=ON long_query_time=2general_log是否开启要非常慎重。如果非开不可,要评估磁盘空间和性能损耗,最好配合日志切割脚本。日志留存期至少满足单位制度要求,一般不低于30天。
备份方案至少要有全备加binlog增量。全备命令:
mysqldump -uroot -p --single-transaction --master-data=2 --all-databases > /backup/all_$(date +%F).sql恢复验证不能只在测评时临时做。建议每季度做一次完整的恢复演练,记录恢复时间、数据条数、异常处理过程。等保测评看到“最近一次恢复演练”有明确记录,这项得分会稳很多。
5.4 数据库安装、迁移与结构变更时也要留等保痕迹
很多团队是等保测评前才开始补安全配置,其实从数据库安装那一刻就应该带着等保思路。
新部署MySQL时,在Linux离线环境下要校验安装包完整性,建议从官方渠道下载,避免使用来路不明的整合包。安装完成后执行mysql_secure_installation,删除匿名账号、测试库,设置root强口令。然后用CREATE DATABASE创建业务库时,显式指定字符集:
CREATE DATABASE appdb DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;表结构也要从一开始就做好:每张表尽量有主键,字段类型够用即可,不要无脑用TEXT或者超大VARCHAR。实际项目里经常遇到给已有重复数据的表加唯一索引报错,这种问题应该在开发阶段就通过约束和数据清洗解决,而不是上线后靠运气。
如果涉及数据库迁移,比如从MySQL转到达梦数据库,等保测评也要重新对标。命令、权限模型、审计方式都会有差异,不能简单认为“业务能跑就行”。迁移前先梳理两张表:一张是数据类型映射,一张是SQL语法差异。主键、自增列、唯一索引、日期函数都要逐项验证。迁移后要做完整的功能测试和恢复演练,形成文档。
Java应用开发中,连接数据库不要硬编码口令。把账号密码放到配置中心或环境变量里,通过权限管理控制谁能读配置。这是等保“配置安全”的一部分,也是我见过最容易反复整改的地方。
最后说一个我自己的习惯:现场测评MySQL时,我会在每条命令后面都加上“当前实例版本”和“当前时间”,因为同一个命令在不同版本下的结果含义可能完全不同。如果客户用的还是老版本,我会先把版本列为记录项,再逐条检查。做测评不是背命令,而是理解每条命令背后的安全意图;能跟客户解释清楚“为什么查这个”,整改推进才会顺利。