mysql 的 version_banner 无法通过配置关闭,因其由协议层硬编码决定:tcp 握手包中 server_version 字段在认证前明文发送,my.cnf 设置、version_comment 修改或 version_tokens 插件均只影响 sql 层返回值,不干预握手过程;唯一彻底方案是修改源码中 server_version 初始化值并重编译 mysqld,或使用 proxysql 2.4+ 的 mysql-server_version 变量代理覆盖。

MySQL 的 version_banner 无法通过配置关闭,这是协议层硬编码行为——只要 TCP 连接建立,服务端就在初始握手包里明文发送类似 8.0.33 或 5.7.42-log 的字符串。改 my.cnf、设 version_comment、关 version_tokens 全部无效。
为什么 show_version=OFF 或 SET GLOBAL version_comment 没用
这些操作只影响 SQL 层返回值(如 SELECT VERSION()、SHOW VARIABLES LIKE 'version'),而攻击者根本不需要登录:用 nc -w1 localhost 3306 | head -c100 或 nmap -sV -p3306 target 就能直接拿到 banner。MySQL 协议规定 handshake response packet 中必须携带 server_version 字段,且该字段在认证前就已发出,不在 SQL 解析范围内。
-
show_version = OFF是完全不存在的配置项,my.cnf中加了也无任何效果 -
SET GLOBAL version_comment = 'xxx'只改变SELECT @@version_comment输出,不影响握手包 -
version_tokens插件仅控制SELECT VERSION()的字符串组成,对 TCP banner 零干预
修改 mysqld 源码替换 server_version 字符串
这是唯一能从服务端根除 banner 版本号的方式,但代价高、风险大,仅推荐可控自建环境使用。关键不是“删掉”,而是替换成固定、合法、非空的字符串,否则部分 JDBC/ODBC 驱动会解析失败并抛 CommunicationsException。
- MySQL 5.7:修改
sql/mysqld.cc中全局变量server_version的初始化值,例如改为"5.7.0"或"mysql-server" - MySQL 8.0+:搜索
server_version_str,通常位于sql/server_components/component_implementation.cc或sql/mysqld.h,同样替换为固定值 - 必须完整重新编译
mysqld(make && make install),仅 patch 二进制文件或替换可执行体不可靠 - 验证方式:用
tcpdump -i lo port 3306 -A -c1抓一次连接,找握手响应包中00 00 00 00后紧跟的 ASCII 字符串,确认已变更
ProxySQL 能否真正屏蔽 banner?
可以,但仅限 ProxySQL 作为 MySQL 协议代理时启用 mysql-server_version admin 变量;HAProxy、nginx stream、mysql-proxy 的 Lua 插件均无法安全修改 handshake packet。
- ProxySQL 2.4+ 支持在 Admin 界面运行:
SET mysql-server_version='5.5.55',该值会覆盖原始 banner 并出现在 handshake 包中 - 必须开启
mysql-forwarding模式,且客户端直连 ProxySQL(而非后端 mysqld) - HAProxy 的
tcp-response content replace在 MySQL 协议下极不稳定:handshake 包长度可变、含随机 salt、version 字符串位置不固定,极易错替或截断 - mysql-proxy 的 Lua 回调(如
read_handshake_response)只能拦截 SQL 流量,无法修改初始 handshake response payload
最容易被忽略的泄露点:权限与日志
即使 banner 和 SELECT VERSION() 都被处理了,仍可能通过其他路径暴露真实版本:
- 普通账号若拥有
SELECT权限,执行SELECT @@version_compile_machine, @@version_compile_os仍可推断版本细节 - 错误日志中若开启
log_error_verbosity = 3,部分内部错误会打印带版本标识的堆栈 - Docker 镜像标签、K8s Pod 注解、CI/CD 构建日志、甚至 SQL 注释(如
/* mysql-5.7.42 */)都可能成为指纹来源 - phpMyAdmin 等管理工具若未设
$cfg['ShowVersion'] = false,且 PHP 暴露expose_php = On,会叠加泄露多层信息











