sidorares/node-mysql2 · error · Error
Unexpected data in AuthMoreData packet received by
Error message
Unexpected data in AuthMoreData packet received by ${PLUGIN_NAME} plugin in STATE_FINAL state. What it means
Thrown by caching_sha2_password when the plugin has already reached STATE_FINAL (-1) — meaning authentication is logically complete — yet the server sends another AuthMoreData packet (lib/auth_plugins/caching_sha2_password.js:99-102). In a well-formed exchange no further packets should arrive after STATE_FINAL, so this signals a protocol desync or an out-of-band packet arriving on a dead connection.
Solutions
- Reproduce against a direct, non-pooled connection to rule out socket reuse.
- Upgrade mysql2 to the current release to pick up state-machine fixes for newer server versions.
- If pooling, ensure connections are fully closed on error rather than returned to the pool (set the pool error handlers to destroy).
- Capture the wire exchange with a packet trace to identify the unexpected trailing packet and report it upstream.
Example fix
// before: errored connection silently returned to pool
pool.on('connection', (c) => c.on('error', () => {}));
// after: destroy errored connections so auth state resets
pool.on('connection', (c) => c.on('error', () => { c.destroy(); })); Defensive patterns
Strategy: try-catch
Try / catch
try {
await conn.connect();
} catch (e) {
if (/STATE_FINAL/.test(e.message)) { conn.destroy(); throw new Error('auth desync, retry on fresh socket'); }
throw e;
} Prevention
- Destroy (not return) pooled connections that error during auth.
- Avoid sharing a socket across concurrent handshakes.
- Upgrade mysql2 and the server together.
When it happens
Trigger: The server sends an extra trailing byte after the fast-auth-success path (line 68-70 set STATE_FINAL and returned null, but a subsequent AuthMoreData packet still arrives); reuse of a pooled connection whose previous auth state was not fully reset; a server-side protocol extension emitting an unsolicited AuthMoreData that mysql2 does not yet understand.
Common situations: Connection pool reusing a socket whose prior session ended abnormally; a MySQL/MariaDB fork that adds extra auth-roundtrip bytes; version skew between an older mysql2 client and a newer server that appends a metadata packet post-auth.
Related errors
- Invalid AuthMoreData packet received by
- Unexpected data in AuthMoreData packet received by
- Unexpected data in AuthMoreData packet received by
- AuthPluginMoreData received but no auth plugin instance…
- HandshakeResponse authPluginName must be a string when…
AI-assisted analysis of sidorares/node-mysql2@8b1f829d37 (2026-08-11).
Data as JSON: /api/errors/90adede8847b0a77.
Report an issue: GitHub.
Appendix: source
Thrown at lib/auth_plugins/caching_sha2_password.js:100
// if client provides key we can save one extra roundrip on first connection
if (pluginOptions.serverPublicKey) {
return authWithKey(pluginOptions.serverPublicKey);
}
state = STATE_WAIT_SERVER_KEY;
return REQUEST_SERVER_KEY_PACKET;
}
throw new Error(
`Invalid AuthMoreData packet received by ${PLUGIN_NAME} plugin in STATE_TOKEN_SENT state.`
);
case STATE_WAIT_SERVER_KEY:
if (pluginOptions.onServerPublicKey) {
pluginOptions.onServerPublicKey(data);
}
return authWithKey(data);
case STATE_FINAL:
throw new Error(
`Unexpected data in AuthMoreData packet received by ${PLUGIN_NAME} plugin in STATE_FINAL state.`
);
}
throw new Error(
`Unexpected data in AuthMoreData packet received by ${PLUGIN_NAME} plugin in state ${state}`
);
};
};
// Export the plugin factory as default
module.exports = pluginFactory;
// Export calculateToken for reuse in initial handshake optimization
module.exports.calculateToken = calculateToken;
View on GitHub (pinned to 8b1f829d37)