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

  1. Reproduce against a direct, non-pooled connection to rule out socket reuse.
  2. Upgrade mysql2 to the current release to pick up state-machine fixes for newer server versions.
  3. If pooling, ensure connections are fully closed on error rather than returned to the pool (set the pool error handlers to destroy).
  4. 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

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


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)