{"record":{"id":"256b1b61a595aef5","repo":"sidorares/node-mysql2","slug":"invalid-authmoredata-packet-received-by-plugin-n","errorCode":null,"errorMessage":"Invalid AuthMoreData packet received by ${PLUGIN_NAME} plugin in STATE_TOKEN_SENT state.","messagePattern":"Invalid AuthMoreData packet received by (.+?) plugin in STATE_TOKEN_SENT state\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"lib/auth_plugins/caching_sha2_password.js","lineNumber":91,"sourceCode":"          if (PERFORM_FULL_AUTHENTICATION_PACKET.equals(data)) {\n            const isSecureConnection =\n              typeof pluginOptions.overrideIsSecure === 'undefined'\n                ? connection.config.ssl || connection.config.socketPath\n                : pluginOptions.overrideIsSecure;\n            if (isSecureConnection) {\n              state = STATE_FINAL;\n              return Buffer.from(`${password}\\0`, 'utf8');\n            }\n\n            // if client provides key we can save one extra roundrip on first connection\n            if (pluginOptions.serverPublicKey) {\n              return authWithKey(pluginOptions.serverPublicKey);\n            }\n\n            state = STATE_WAIT_SERVER_KEY;\n            return REQUEST_SERVER_KEY_PACKET;\n          }\n          throw new Error(\n            `Invalid AuthMoreData packet received by ${PLUGIN_NAME} plugin in STATE_TOKEN_SENT state.`\n          );\n        case STATE_WAIT_SERVER_KEY:\n          if (pluginOptions.onServerPublicKey) {\n            pluginOptions.onServerPublicKey(data);\n          }\n          return authWithKey(data);\n        case STATE_FINAL:\n          throw new Error(\n            `Unexpected data in AuthMoreData packet received by ${PLUGIN_NAME} plugin in STATE_FINAL state.`\n          );\n      }\n\n      throw new Error(\n        `Unexpected data in AuthMoreData packet received by ${PLUGIN_NAME} plugin in state ${state}`\n      );\n    };\n  };","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/sidorares/node-mysql2/blob/8b1f829d3706404ab372cf97bd77ebcf86578d97/lib/auth_plugins/caching_sha2_password.js#L73-L109","documentation":"Thrown by the caching_sha2_password auth plugin when, after the client sent its scrambled password token (STATE_TOKEN_SENT), the server replies with an AuthMoreData packet whose first byte is neither 0x03 (fast-auth success) nor 0x04 (perform full authentication). The plugin's state machine at lib/auth_plugins/caching_sha2_password.js:67-93 only recognizes those two bytes, so any other leading byte is treated as a protocol violation. It almost always indicates a malformed or intercepted auth exchange rather than a normal client misconfiguration.","triggerScenarios":"Connecting to a MySQL 8.x server whose default auth plugin is caching_sha2_password, where an intermediary (proxy, man-in-the-middle, buggy connection pooler like a stale PgBouncer-style proxy) rewrites or truncates the AuthMoreData packet. Also reproducible when the server's cached auth state is corrupted, or when the connection is half-closed and stale bytes are read as an auth packet.","commonSituations":"Upgrading a MySQL server from 5.7 (mysql_native_password) to 8.x (caching_sha2_password) behind a proxy that does not understand the new plugin's multi-step flow; using a load balancer that buffers/rewrites auth packets; a network device corrupting the SSL handshake so the client misreads encrypted bytes as a cleartext AuthMoreData packet.","solutions":["Verify the MySQL server version and that no proxy/pooler is intercepting the auth handshake (connect directly to the mysqld port).","Force a clear protocol by either enabling SSL (set config.ssl) or downgrading the server account to mysql_native_password (ALTER USER ... IDENTIFIED WITH mysql_native_password) to bypass caching_sha2_password entirely.","If a proxy is required, upgrade or reconfigure it to be transparent for the auth phase, or pin the connection to a single backend node.","Update mysql2 to the latest release, since auth-state-machine fixes land frequently."],"exampleFix":"// before: plaintext connection through an intercepting proxy\nconst conn = mysql.createConnection({ host: 'proxy', user: 'u', password: 'p' });\n\n// after: TLS so the proxy cannot rewrite the auth exchange\nconst conn = mysql.createConnection({ host: 'db', user: 'u', password: 'p', ssl: { rejectUnauthorized: true } });","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const conn = await mysql.createConnection({ host, user, password, ssl: { rejectUnauthorized: true } });\n} catch (e) {\n  if (/caching_sha2_password.*STATE_TOKEN_SENT/.test(e.message)) {\n    // auth exchange tampered/proxied: bypass proxy or enable TLS\n  }\n  throw e;\n}","preventionTips":["Always enable TLS (config.ssl) for caching_sha2_password so the full-auth RSA path is avoided.","Connect directly to mysqld during debugging to rule out intercepting proxies.","Keep mysql2 on the latest release to pick up auth state-machine fixes."],"tags":["authentication","caching-sha2-password","network","protocol"],"backgroundTag":null,"analyzedSha":"8b1f829d3706404ab372cf97bd77ebcf86578d97","analyzedAt":"2026-08-11T02:54:28.964Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}