projectdiscovery/nuclei · warning
mysql handshake filler byte is not zero
Error message
mysql handshake filler byte is not zero
What it means
Thrown by the MySQL fingerprint parser while decoding the server's initial handshake (greeting) packet. After reading the NUL-terminated server version string starting at offset 5, the parser expects the fingerprintx packet layout: 4-byte thread id, 8-byte auth-plugin-data part 1, and then a filler byte at nullPos+13 that must be 0x00. A non-zero byte at that position means the greeting does not match the MySQL wire format, so the fingerprint is rejected. The error propagates out of mysql.IsMySQL / FingerprintMySQL (and thus Connect / ExecuteQuery, which call IsMySQL first).
Source
Thrown at pkg/js/libs/mysql/fingerprint.go:249
length := mysqlPacketLength(packet)
if length < 25 || length > 4096 {
return "", 0, fmt.Errorf("mysql handshake packet length out of range")
}
if packet[4] != mysqlProtocolVersion10 {
return "", 0, fmt.Errorf("unsupported mysql protocol version")
}
version, nullPos, err := readNullTerminatedASCIIString(packet, 5)
if err != nil {
return "", 0, err
}
// nullPos points at the NUL; fingerprintx filler is at nullPos+13.
fillerPos := nullPos + 13
if fillerPos >= len(packet) {
return "", 0, fmt.Errorf("mysql handshake missing filler byte")
}
if packet[fillerPos] != 0x00 {
return "", 0, fmt.Errorf("mysql handshake filler byte is not zero")
}
return version, nullPos + 1, nil
}
func enrichMySQLHandshake(info *HandshakeInfo, packet []byte, versionEnd int) {
length := mysqlPacketLength(packet)
if length+4 > len(packet) {
length = len(packet) - 4
}
if length <= 0 {
return
}
payload := packet[4 : 4+length]
// versionEnd is absolute index of first byte after version NUL in packet.
pos := versionEnd - 4
if pos < 0 || pos > len(payload) {
return
}View on GitHub (pinned to 265b3a3dec)
Solutions
- Confirm the target is really MySQL on that port (e.g. `mysql -h host -P port -u x` or an nmap mysql probe) and fix the port in the template
- Treat this error as 'not MySQL' in the template logic and continue scanning other ports — it is an expected probe outcome, not a bug
- If the target should be MySQL, capture the raw greeting (hexdump the first packet) and verify byte 0 is protocol version 0x0a and a 0x00 filler exists 13 bytes after the version's NUL terminator
- Check for transparent proxies / IPS devices between scanner and target that may rewrite the banner
Example fix
// before
const info = mysql.FingerprintMySQL('acme.com', 3306);
log(to_json(info)); // error kills the script on non-mysql targets
// after
try {
const info = mysql.FingerprintMySQL('acme.com', 3306);
log(to_json(info));
} catch (e) {
log('not a mysql service: ' + e); // keep scanning
} Defensive patterns
Strategy: try-catch
Validate before calling
// cheap pre-check: read the greeting and verify MySQL protocol version 0x0a
const conn = net.Open('tcp', host + ':' + port);
const banner = conn.Recv(128);
conn.Close();
if (banner.charCodeAt(4) !== 0x0a) { log('not mysql, skip'); } Type guard
function looksLikeMysqlGreeting(b) {
return b && b.length > 5 && b.charCodeAt(4) === 0x0a && b.indexOf('\u0000', 5) !== -1;
} Try / catch
try {
const info = mysql.FingerprintMySQL(host, port);
} catch (e) {
// any fingerprint parse error === treat as non-mysql, continue template
log('fingerprint rejected: ' + e);
} Prevention
- Always gate mysql.Connect/ExecuteQuery behind mysql.IsMySQL
- Treat fingerprint parse errors as negative probe results, never as template failures
- Prefer the default port or a verified port map instead of probing arbitrary ports
- Remember IsMySQL/FingerprintMySQL results are memoized per execution — one bad probe answer is cached
When it happens
Trigger: Calling mysql.IsMySQL, mysql.FingerprintMySQL, mysql.Connect or mysql.ExecuteQuery against a TCP port where something answers with bytes but is not a real MySQL server (e.g. another database, a custom TCP service, or a proxy that rewrites the banner). Concretely: the version string parses fine, but packet[nullPos+13] != 0x00.
Common situations: Scanning a port list where 3306 is actually served by another protocol; MySQL-compatible forks or intermediaries that alter the greeting header layout; TLS-wrapped MySQL ports probed in plaintext producing a parseable-looking prefix but garbage filler byte; version-detection templates run against arbitrary open ports.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- empty mysql greeting
- invalid mysql packet length %d
- mysql handshake packet too short
- mysql handshake packet length out of range
- unsupported mysql protocol version
AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15).
Data as JSON: /api/errors/a3214f86b0d83900.
Report an issue: GitHub.