{"record":{"id":"e7714f761df5173d","repo":"apache/seatunnel","slug":"user-does-not-have-the-lock-tables-privilege-req","errorCode":null,"errorMessage":"User does not have the 'LOCK TABLES' privilege required to obtain a consistent snapshot by preventing concurrent writes to tables.","messagePattern":"User does not have the 'LOCK TABLES' privilege required to obtain a consistent snapshot by preventing concurrent writes to tables\\.","errorType":"exception","errorClass":"DebeziumException","httpStatus":null,"severity":"error","filePath":"seatunnel-connectors-v2/connector-cdc/connector-cdc-mysql/src/main/java/io/debezium/connector/mysql/MySqlSnapshotChangeEventSource.java","lineNumber":566,"sourceCode":"                \"Writes to MySQL tables prevented for a total of {}\",\n                Strings.duration(lockReleased - globalLockAcquiredAt));\n        globalLockAcquiredAt = -1;\n    }\n\n    private void tableLock(\n            RelationalSnapshotContext<MySqlPartition, MySqlOffsetContext> snapshotContext)\n            throws SQLException {\n        // ------------------------------------\n        // LOCK TABLES and READ BINLOG POSITION\n        // ------------------------------------\n        // We were not able to acquire the global read lock, so instead we have to obtain a read\n        // lock on each table.\n        // This requires different privileges than normal, and also means we can't unlock the tables\n        // without\n        // implicitly committing our transaction ...\n        if (!connection.userHasPrivileges(\"LOCK TABLES\")) {\n            // We don't have the right privileges\n            throw new DebeziumException(\n                    \"User does not have the 'LOCK TABLES' privilege required to obtain a \"\n                            + \"consistent snapshot by preventing concurrent writes to tables.\");\n        }\n        // We have the required privileges, so try to lock all of the tables we're interested in ...\n        LOGGER.info(\n                \"Flush and obtain read lock for {} tables (preventing writes)\",\n                snapshotContext.capturedTables);\n        if (!snapshotContext.capturedTables.isEmpty()) {\n            final String tableList =\n                    snapshotContext.capturedTables.stream()\n                            .map(tid -> quote(tid))\n                            .collect(Collectors.joining(\",\"));\n            connection.executeWithoutCommitting(\"FLUSH TABLES \" + tableList + \" WITH READ LOCK\");\n        }\n        tableLockAcquiredAt = clock.currentTimeInMillis();\n        metrics.globalLockAcquired();\n    }\n","sourceCodeStart":548,"sourceCodeEnd":584,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-cdc/connector-cdc-mysql/src/main/java/io/debezium/connector/mysql/MySqlSnapshotChangeEventSource.java#L548-L584","documentation":"When the MySQL connector cannot use a consistent global read lock (MySqlConnector's minimal blocking strategy falls back to table-level locking), it needs to LOCK TABLES on every table being snapshotted so concurrent writes cannot corrupt snapshot consistency. Before doing so it checks the account privileges; if the MySQL user lacks the LOCK TABLES privilege it throws this DebeziumException instead of silently producing an inconsistent snapshot.","triggerScenarios":"snapshot.locking.mode is not 'none' and the configured MySQL user fails connection.userHasPrivileges(\"LOCK TABLES\") during the tableLock phase of the snapshot, i.e. the account was never granted LOCK TABLES (a global/static privilege grantable only at global level).","commonSituations":"Using a least-privilege CDC account with only SELECT/REPLICATION privileges; cloud-managed MySQL where the DBA did not grant LOCK TABLES; connector configs that disable minimal blocking so the table-lock path runs (e.g. explicit execute.blocking.thread or minimal blocked without privileges for FLUSH TABLES WITH READ LOCK fallback).","solutions":["Grant the CDC user the privilege: `GRANT LOCK TABLES ON *.* TO 'user'@'host';` then FLUSH PRIVILEGES and restart the connector.","If a consistent snapshot is not required for your setup, set `snapshot.locking.mode=none` (only safe when no concurrent writes occur or snapshot happens on a quiesced replica).","Run the snapshot against a read replica where writes are blocked and minimal locking can be avoided.","Verify with `SHOW GRANTS FOR 'user'@'host';` that LOCK TABLES is actually present for the exact host the connector connects from."],"exampleFix":"// before (connector user created without locking rights)\nCREATE USER 'st_cdc'@'%' IDENTIFIED BY '***';\nGRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'st_cdc'@'%';\n\n// after\nCREATE USER 'st_cdc'@'%' IDENTIFIED BY '***';\nGRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT, LOCK TABLES ON *.* TO 'st_cdc'@'%';\nFLUSH PRIVILEGES;","handlingStrategy":"validation","validationCode":"// validate CDC user privileges before starting the connector\ntry (Connection c = DriverManager.getConnection(url, user, pass);\n     Statement s = c.createStatement();\n     ResultSet rs = s.executeQuery(\"SHOW GRANTS FOR CURRENT_USER()\")) {\n  boolean hasLock = false;\n  while (rs.next()) {\n    if (rs.getString(1).toUpperCase().contains(\"LOCK TABLES\")) { hasLock = true; }\n  }\n  if (!hasLock) throw new IllegalStateException(\"CDC user lacks LOCK TABLES privilege\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  startConnector(config);\n} catch (DebeziumException e) {\n  if (e.getMessage().contains(\"'LOCK TABLES' privilege\")) {\n    // remediate: GRANT LOCK TABLES ON *.* TO user@host, or set snapshot.locking.mode=none\n  } else throw e;\n}","preventionTips":["Standardize a CDC provisioning script that grants SELECT, REPLICATION SLAVE, REPLICATION CLIENT and LOCK TABLES","Run `SHOW GRANTS` in pre-deployment checks","On managed MySQL, confirm the cloud platform permits global LOCK TABLES grant","Prefer snapshot.locking.mode=none on read replicas where writes are already blocked"],"tags":["mysql","privileges","snapshot","locking","cdc"],"backgroundTag":"insufficient-permissions","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}