Repository: confluentinc/debezium
Pull request #110: CC-31385: add iam assume role support
Author: login: sangeet259
Created: 2025-03-24T17:26:54Z | Merged: 2025-04-17T11:55:47Z

## Description

Use [AwsChainedAssumeRoleRdsCredsProvider](https://github.com/confluentinc/credential-providers/blob/master/src/main/java/io/confluent/credentialproviders/aws/AwsChainedAssumeRoleRdsCredsProvider.java) to support IAM Assume Role based Auth.

## Testing
https://confluentinc.atlassian.net/wiki/spaces/~6378a3bd5fc160544e18583c/pages/4250894429/Test+Plan+IAM+Assume+Role+Support+in+MySQL+Debezium+CDC+Source+Connector



Diff:
diff --git a/debezium-connector-mysql/pom.xml b/debezium-connector-mysql/pom.xml
index 3665e55fdb9..b13e407d151 100644
--- a/debezium-connector-mysql/pom.xml
+++ b/debezium-connector-mysql/pom.xml
@@ -57,6 +57,12 @@
                 </exclusion>
             </exclusions>
         </dependency>
+        <dependency>
+            <groupId>io.confluent</groupId>
+            <artifactId>credential-providers</artifactId>
+            <version>${credential.providers.version}</version>
+        </dependency>
+
 
         <!-- Testing -->
         <dependency>
@@ -172,6 +178,8 @@
         <mysql.init.timeout>60000</mysql.init.timeout> <!-- 60 seconds -->
         <apicurio.port>8080</apicurio.port>
         <apicurio.init.timeout>60000</apicurio.init.timeout> <!-- 60 seconds -->
+        <credential.providers.version>0.14.0</credential.providers.version>
+
         <!--
         By default, we should use the docker image maintained by the MySQL team. This property is changed with different profiles.
         However, we run one container with GTIDs and one without.
diff --git a/debezium-connector-mysql/src/main/java/io/debezium/connector/mysql/MySqlConnection.java b/debezium-connector-mysql/src/main/java/io/debezium/connector/mysql/MySqlConnection.java
index 250b96c5602..7c3aefe6739 100644
--- a/debezium-connector-mysql/src/main/java/io/debezium/connector/mysql/MySqlConnection.java
+++ b/debezium-connector-mysql/src/main/java/io/debezium/connector/mysql/MySqlConnection.java
@@ -18,12 +18,15 @@
 import java.util.List;
 import java.util.Map;
 import java.util.OptionalLong;
+import java.util.Properties;
+
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.mysql.cj.CharsetMapping;
 
+import io.confluent.credentialproviders.JdbcCredentials;
 import io.debezium.DebeziumException;
 import io.debezium.config.CommonConnectorConfig;
 import io.debezium.config.CommonConnectorConfig.EventProcessingFailureHandlingMode;
@@ -508,12 +511,14 @@ public static class MySqlConnectionConfiguration {
         private final JdbcConfiguration jdbcConfig;
         private final ConnectionFactory factory;
         private final Configuration config;
+        private final MySqlConnectorConfig connectorConfig;
 
         public MySqlConnectionConfiguration(Configuration config) {
             // Set up the JDBC connection without actually connecting, with extra MySQL-specific properties
             // to give us better JDBC database metadata behavior, including using UTF-8 for the client-side character encoding
             // per https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-charsets.html
             this.config = config;
+            this.connectorConfig = new MySqlConnectorConfig(config);
             final boolean useSSL = sslModeEnabled();
             final Configuration dbConfig = config
                     .edit()
@@ -556,7 +561,13 @@ public MySqlConnectionConfiguration(Configuration config) {
             String driverClassName = this.config.getString(MySqlConnectorConfig.JDBC_DRIVER);
             Field protocol = MySqlConnectorConfig.JDBC_PROTOCOL;
 
-            factory = JdbcConnection.patternBasedFactory(MySqlConnection.URL_PATTERN, driverClassName, getClass().getClassLoader(), protocol);
+            ConnectionFactory baseFactory = JdbcConnection.patternBasedFactory(MySqlConnection.URL_PATTERN, driverClassName, getClass().getClassLoader(), protocol);
+            factory = jdbcConfig -> {
+                Properties props = jdbcConfig.asProperties();
+                props.setProperty(JdbcConfiguration.USER.name(), username());
+                props.setProperty(JdbcConfiguration.PASSWORD.name(), password());
+                return baseFactory.connect(JdbcConfiguration.adapt(Configuration.from(props)));
+            };
         }
 
         private static String determineConnectionTimeZone(final Configuration dbConfig) {
@@ -583,11 +594,11 @@ public ConnectionFactory factory() {
         }
 
         public String username() {
-            return config.getString(MySqlConnectorConfig.USER);
+            return connectorConfig.username();
         }
 
         public String password() {
-            return config.getString(MySqlConnectorConfig.PASSWORD);
+            return connectorConfig.password();
         }
 
         public String hostname() {
diff --git a/debezium-connector-mysql/src/main/java/io/debezium/connector/mysql/MySqlConnector.java b/debezium-connector-mysql/src/main/java/io/debezium/connector/mysql/MySqlConnector.java
index e1fd403693f..4e7b273d666 100644
--- a/debezium-connector-mysql/src/main/java/io/debezium/connector/mysql/MySqlConnector.java
+++ b/debezium-connector-mysql/src/main/java/io/debezium/connector/mysql/MySqlConnector.java
@@ -81,6 +81,7 @@ protected void validateConnection(Map<String, ConfigValue> configValues, Configu
         ConfigValue hostnameValue = configValues.get(RelationalDatabaseConnectorConfig.HOSTNAME.name());
         // Try to connect to the database ...
         final MySqlConnectionConfiguration connectionConfig = new MySqlConnectionConfiguration(config);
+
         try (MySqlConnection connection = new MySqlConnection(connectionConfig)) {
             try {
                 connection.connect();
diff --git a/debezium-connector-mysql/src/main/java/io/debezium/connector/mysql/MySqlConnectorConfig.java b/debezium-connector-mysql/src/main/java/io/debezium/connector/mysql/MySqlConnectorConfig.java
index 81670c9cc54..f8f5e7570df 100644
--- a/debezium-connector-mysql/src/main/java/io/debezium/connector/mysql/MySqlConnectorConfig.java
+++ b/debezium-connector-mysql/src/main/java/io/debezium/connector/mysql/MySqlConnectorConfig.java
@@ -17,6 +17,8 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import io.confluent.credentialproviders.JdbcCredentialsProvider;
+import io.debezium.DebeziumException;
 import io.debezium.config.CommonConnectorConfig;
 import io.debezium.config.ConfigDefinition;
 import io.debezium.config.Configuration;
@@ -42,6 +44,8 @@
  */
 public class MySqlConnectorConfig extends HistorizedRelationalDatabaseConnectorConfig {
 
+    private final JdbcCredentialsProvider credsProvider;
+
     private static final Logger LOGGER = LoggerFactory.getLogger(MySqlConnectorConfig.class);
 
     /**
@@ -624,10 +628,20 @@ public static SecureConnectionMode parse(String value, String defaultValue) {
             .withValidation(Field::isClassName)
             .withDescription("JDBC Driver class name used to connect to the MySQL database server.");
 
+    public static final Field CREDENTIALS_PROVIDER_CLASS_NAME = Field.create("jdbc.creds.provider.class.name")
+            .withDisplayName("JDBC Credentials Provider Class Name")
+            .withType(Type.STRING)
+            .withGroup(Field.createGroupEntry(Field.Group.CONNECTION, 42))
+            .withWidth(Width.MEDIUM)
+            .withDefault("io.confluent.credentialproviders.DefaultJdbcCredentialsProvider")
+            .withImportance(Importance.LOW)
+            .withValidation(Field::isOptional)
+            .withDescription("JDBC Credentials Provider class name used to provide credentials for connecting to the MySQL database server.");
+
     public static final Field JDBC_PROTOCOL = Field.create(DATABASE_CONFIG_PREFIX + "protocol")
             .withDisplayName("JDBC Protocol")
             .withType(Type.STRING)
-            .withGroup(Field.createGroupEntry(Field.Group.CONNECTION, 42))
+            .withGroup(Field.createGroupEntry(Field.Group.CONNECTION, 43))
             .withWidth(Width.MEDIUM)
             .withDefault("jdbc:mysql")
             .withImportance(Importance.LOW)
@@ -891,6 +905,7 @@ public static SecureConnectionMode parse(String value, String defaultValue) {
                     ON_CONNECT_STATEMENTS,
                     SERVER_ID,
                     SERVER_ID_OFFSET,
+                    CREDENTIALS_PROVIDER_CLASS_NAME,
                     SSL_MODE,
                     SSL_KEYSTORE,
                     SSL_KEYSTORE_PASSWORD,
@@ -959,8 +974,12 @@ protected boolean supportsSchemaChangesDuringIncrementalSnapshot() {
     private final Predicate<String> gtidSourceFilter;
     private final EventProcessingFailureHandlingMode inconsistentSchemaFailureHandlingMode;
     private final boolean readOnlyConnection;
-
     public MySqlConnectorConfig(Configuration config) {
+        this(config, getCredentialsProvider(config));
+    }
+    
+    // visible for testing
+    public MySqlConnectorConfig(Configuration config, JdbcCredentialsProvider credsProvider) {
         super(
                 MySqlConnector.class,
                 config,
@@ -991,6 +1010,7 @@ public MySqlConnectorConfig(Configuration config) {
                 : (gtidSetExcludes != null ? Predicates.excludesUuids(gtidSetExcludes) : null);
 
         this.storeOnlyCapturedDatabasesDdl = config.getBoolean(STORE_ONLY_CAPTURED_DATABASES_DDL);
+        this.credsProvider = credsProvider;
     }
 
     public boolean useCursorFetch() {
@@ -1014,6 +1034,23 @@ private static int validateEventDeserializationFailureHandlingModeNotSet(Configu
         return 0;
     }
 
+    private static JdbcCredentialsProvider getCredentialsProvider(Configuration config) {
+        String providerClass = config.getString(MySqlConnectorConfig.CREDENTIALS_PROVIDER_CLASS_NAME);
+        try {
+            JdbcCredentialsProvider provider = (JdbcCredentialsProvider) Class.forName(providerClass)
+                    .getDeclaredConstructor().newInstance();
+
+            provider.configure(config.asMap());
+            LOGGER.info("Configured credentials provider: {}", provider);
+
+            return provider;
+        }
+        catch (Exception e) {
+            LOGGER.error("Error initializing credentials provider", e);
+            throw new DebeziumException("Failed to initialize credentials provider: " + providerClass, e);
+        }
+    }
+
     private static int validateGtidSetExcludes(Configuration config, Field field, ValidationOutput problems) {
         String includes = config.getString(GTID_SOURCE_INCLUDES);
         String excludes = config.getString(GTID_SOURCE_EXCLUDES);
@@ -1113,11 +1150,11 @@ public int port() {
     }
 
     public String username() {
-        return config.getString(USER);
+        return credsProvider.getJdbcCreds().user();
     }
 
     public String password() {
-        return config.getString(PASSWORD);
+        return credsProvider.getJdbcCreds().password();
     }
 
     public long serverId() {
diff --git a/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/BinlogReaderBufferIT.java b/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/BinlogReaderBufferIT.java
index 24a8b3748e1..c5569ba7eec 100644
--- a/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/BinlogReaderBufferIT.java
+++ b/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/BinlogReaderBufferIT.java
@@ -78,7 +78,9 @@ public void shouldCorrectlyManageRollback() throws SQLException, InterruptedExce
                 .with(MySqlConnectorConfig.HOSTNAME, System.getProperty("database.replica.hostname", "localhost"))
                 .with(MySqlConnectorConfig.PORT, System.getProperty("database.replica.port", "3306"))
                 .with(MySqlConnectorConfig.USER, "snapper")
+                .with("jdbc.creds.provider.user", "snapper")
                 .with(MySqlConnectorConfig.PASSWORD, "snapperpass")
+                .with("jdbc.creds.provider.password", "snapperpass")
                 .with(MySqlConnectorConfig.SERVER_ID, 18765)
                 .with(CommonConnectorConfig.TOPIC_PREFIX, DATABASE.getServerName())
                 .with(MySqlConnectorConfig.POLL_INTERVAL_MS, 10)
@@ -146,7 +148,9 @@ public void shouldProcessSavepoint() throws SQLException, InterruptedException {
                 .with(MySqlConnectorConfig.HOSTNAME, System.getProperty("database.replica.hostname", "localhost"))
                 .with(MySqlConnectorConfig.PORT, System.getProperty("database.replica.port", "3306"))
                 .with(MySqlConnectorConfig.USER, "snapper")
+                .with("jdbc.creds.provider.user", "snapper")
                 .with(MySqlConnectorConfig.PASSWORD, "snapperpass")
+                .with("jdbc.creds.provider.password", "snapperpass")
                 .with(MySqlConnectorConfig.SERVER_ID, 18765)
                 .with(CommonConnectorConfig.TOPIC_PREFIX, DATABASE.getServerName())
                 .with(MySqlConnectorConfig.POLL_INTERVAL_MS, 10)
@@ -207,7 +211,9 @@ public void shouldProcessLargeTransaction() throws SQLException, InterruptedExce
                 .with(MySqlConnectorConfig.HOSTNAME, System.getProperty("database.replica.hostname", "localhost"))
                 .with(MySqlConnectorConfig.PORT, System.getProperty("database.replica.port", "3306"))
                 .with(MySqlConnectorConfig.USER, "snapper")
+                .with("jdbc.creds.provider.user", "snapper")
                 .with(MySqlConnectorConfig.PASSWORD, "snapperpass")
+                .with("jdbc.creds.provider.password", "snapperpass")
                 .with(MySqlConnectorConfig.SERVER_ID, 18765)
                 .with(CommonConnectorConfig.TOPIC_PREFIX, DATABASE.getServerName())
                 .with(MySqlConnectorConfig.POLL_INTERVAL_MS, 10)
@@ -278,7 +284,9 @@ public void shouldProcessRolledBackSavepoint() throws SQLException, InterruptedE
                 .with(MySqlConnectorConfig.HOSTNAME, System.getProperty("database.replica.hostname", "localhost"))
                 .with(MySqlConnectorConfig.PORT, System.getProperty("database.replica.port", "3306"))
                 .with(MySqlConnectorConfig.USER, "snapper")
+                .with("jdbc.creds.provider.user", "snapper")
                 .with(MySqlConnectorConfig.PASSWORD, "snapperpass")
+                .with("jdbc.creds.provider.password", "snapperpass")
                 .with(MySqlConnectorConfig.SERVER_ID, 18765)
                 .with(CommonConnectorConfig.TOPIC_PREFIX, DATABASE.getServerName())
                 .with(MySqlConnectorConfig.POLL_INTERVAL_MS, 10)
diff --git a/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/BlockingSnapshotIT.java b/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/BlockingSnapshotIT.java
index b8de5e13b1d..fd64aba6fc4 100644
--- a/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/BlockingSnapshotIT.java
+++ b/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/BlockingSnapshotIT.java
@@ -62,7 +62,9 @@ protected Configuration.Builder config() {
         return DATABASE.defaultConfig()
                 .with(MySqlConnectorConfig.INCLUDE_SQL_QUERY, true)
                 .with(MySqlConnectorConfig.USER, "mysqluser")
+                .with("jdbc.creds.provider.user", "mysqluser")
                 .with(MySqlConnectorConfig.PASSWORD, "mysqlpw")
+                .with("jdbc.creds.provider.password", "mysqlpw")
                 .with(MySqlConnectorConfig.SNAPSHOT_MODE, MySqlConnectorConfig.SnapshotMode.SCHEMA_ONLY.getValue())
                 .with(MySqlConnectorConfig.INCLUDE_SCHEMA_CHANGES, false)
                 .with(MySqlConnectorConfig.SIGNAL_DATA_COLLECTION, DATABASE.qualifiedTableName("debezium_signal"))
@@ -75,7 +77,9 @@ protected Configuration.Builder mutableConfig(boolean signalTableOnly, boolean s
         return DATABASE.defaultConfig()
                 .with(MySqlConnectorConfig.INCLUDE_SQL_QUERY, true)
                 .with(MySqlConnectorConfig.USER, "mysqluser")
+                .with("jdbc.creds.provider.user", "mysqluser")
                 .with(MySqlConnectorConfig.PASSWORD, "mysqlpw")
+                .with("jdbc.creds.provider.password", "mysqlpw")
                 .with(MySqlConnectorConfig.SNAPSHOT_MODE, MySqlConnectorConfig.SnapshotMode.INITIAL.getValue())
                 .with(MySqlConnectorConfig.INCLUDE_SCHEMA_CHANGES, false)
                 .with(MySqlConnectorConfig.SIGNAL_DATA_COLLECTION, DATABASE.qualifiedTableName("debezium_signal"))
diff --git a/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/IncrementalSnapshotIT.java b/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/IncrementalSnapshotIT.java
index 2df4e54622b..e8b4dbe74ef 100644
--- a/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/IncrementalSnapshotIT.java
+++ b/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/IncrementalSnapshotIT.java
@@ -68,7 +68,9 @@ protected Configuration.Builder config() {
         return DATABASE.defaultConfig()
                 .with(MySqlConnectorConfig.INCLUDE_SQL_QUERY, true)
                 .with(MySqlConnectorConfig.USER, "mysqluser")
+                .with("jdbc.creds.provider.user", "mysqluser")
                 .with(MySqlConnectorConfig.PASSWORD, "mysqlpw")
+                .with("jdbc.creds.provider.password", "mysqlpw")
                 .with(MySqlConnectorConfig.SNAPSHOT_MODE, SnapshotMode.SCHEMA_ONLY.getValue())
                 .with(MySqlConnectorConfig.INCLUDE_SCHEMA_CHANGES, false)
                 .with(MySqlConnectorConfig.SIGNAL_DATA_COLLECTION, DATABASE.qualifiedTableName("debezium_signal"))
@@ -90,7 +92,9 @@ protected Configuration.Builder mutableConfig(boolean signalTableOnly, boolean s
         return DATABASE.defaultConfig()
                 .with(MySqlConnectorConfig.INCLUDE_SQL_QUERY, true)
                 .with(MySqlConnectorConfig.USER, "mysqluser")
+                .with("jdbc.creds.provider.user", "mysqluser")
                 .with(MySqlConnectorConfig.PASSWORD, "mysqlpw")
+                .with("jdbc.creds.provider.password", "mysqlpw")
                 .with(MySqlConnectorConfig.SNAPSHOT_MODE, SnapshotMode.INITIAL.getValue())
                 .with(MySqlConnectorConfig.INCLUDE_SCHEMA_CHANGES, false)
                 .with(MySqlConnectorConfig.SIGNAL_DATA_COLLECTION, DATABASE.qualifiedTableName("debezium_signal"))
diff --git a/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/MySqlConnectorIT.java b/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/MySqlConnectorIT.java
index 230c1149622..7c0d242c934 100644
--- a/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/MySqlConnectorIT.java
+++ b/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/MySqlConnectorIT.java
@@ -28,6 +28,7 @@
 import java.util.stream.Collectors;
 import java.util.stream.StreamSupport;
 
+import io.confluent.credentialproviders.DefaultJdbcCredentialsProvider;
 import org.apache.kafka.common.config.Config;
 import org.apache.kafka.connect.data.Struct;
 import org.apache.kafka.connect.errors.ConnectException;
@@ -658,7 +659,7 @@ private void shouldConsumeAllEventsFromDatabaseUsingSnapshotByField(Field dbIncl
         final String serverName = config.getString(CommonConnectorConfig.TOPIC_PREFIX);
         final MySqlOffsetContext.Loader loader = new MySqlOffsetContext.Loader(new MySqlConnectorConfig(Configuration.create()
                 .with(CommonConnectorConfig.TOPIC_PREFIX, serverName)
-                .build()));
+                .build(), new DefaultJdbcCredentialsProvider()));
         final Map<String, String> partition = new MySqlPartition(serverName, DATABASE.getDatabaseName()).getSourcePartition();
         Map<String, ?> lastCommittedOffset = readLastCommittedOffset(config, partition);
         final MySqlOffsetContext offsetContext = loader.load(lastCommittedOffset);
diff --git a/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/MySqlParserIT.java b/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/MySqlParserIT.java
index 6a4a4c0cba9..e1bf040e938 100644
--- a/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/MySqlParserIT.java
+++ b/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/MySqlParserIT.java
@@ -80,7 +80,9 @@ public Configuration.Builder defaultConfig() {
                 .with(MySqlConnectorConfig.HOSTNAME, System.getProperty("database.hostname", "localhost"))
                 .with(CommonConnectorConfig.DATABASE_CONFIG_PREFIX + JdbcConfiguration.PORT, mySQLContainer.getMappedPort(3306))
                 .with(MySqlConnectorConfig.USER, "debezium")
+                .with("jdbc.creds.provider.user", "debezium")
                 .with(MySqlConnectorConfig.PASSWORD, "dbz")
+                .with("jdbc.creds.provider.password", "dbz")
                 .with(MySqlConnectorConfig.SNAPSHOT_MODE, MySqlConnectorConfig.SnapshotMode.INITIAL)
                 .with(MySqlConnectorConfig.SSL_MODE, MySqlConnectorConfig.SecureConnectionMode.DISABLED)
                 .with(MySqlConnectorConfig.SERVER_ID, 18765)
diff --git a/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/SnapshotSourceIT.java b/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/SnapshotSourceIT.java
index 3be9cab2d87..779da2971f1 100644
--- a/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/SnapshotSourceIT.java
+++ b/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/SnapshotSourceIT.java
@@ -140,7 +140,9 @@ private void snapshotOfSingleDatabase(boolean useGlobalLock, boolean storeOnlyCa
         if (!useGlobalLock) {
             builder
                     .with(MySqlConnectorConfig.USER, "cloud")
+                    .with("jdbc.creds.provider.user", "cloud")
                     .with(MySqlConnectorConfig.PASSWORD, "cloudpass")
+                    .with("jdbc.creds.provider.password", "cloudpass")
                     .with(MySqlConnectorConfig.TEST_DISABLE_GLOBAL_LOCKING, "true")
                     .with(SchemaHistory.STORE_ONLY_CAPTURED_TABLES_DDL, storeOnlyCapturedTables);
         }
@@ -266,7 +268,9 @@ else if (Objects.equals(previousSnapshotSourceField, "last_in_data_collection"))
     public void snapshotWithBackupLocksShouldNotWaitForReads() throws Exception {
         config = simpleConfig()
                 .with(MySqlConnectorConfig.USER, "cloud")
+                .with("jdbc.creds.provider.user", "cloud")
                 .with(MySqlConnectorConfig.PASSWORD, "cloudpass")
+                .with("jdbc.creds.provider.password", "cloudpass")
                 .with(MySqlConnectorConfig.SNAPSHOT_LOCKING_MODE, MySqlConnectorConfig.SnapshotLockingMode.MINIMAL_PERCONA)
                 .build();
 
diff --git a/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/SourceInfoTest.java b/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/SourceInfoTest.java
index fae573e2f71..ff8e5955b8c 100644
--- a/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/SourceInfoTest.java
+++ b/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/SourceInfoTest.java
@@ -15,6 +15,7 @@
 import java.util.UUID;
 import java.util.function.Predicate;
 
+import io.confluent.credentialproviders.DefaultJdbcCredentialsProvider;
 import org.apache.kafka.connect.data.Schema;
 import org.apache.kafka.connect.data.SchemaBuilder;
 import org.apache.kafka.connect.data.Struct;
@@ -48,9 +49,14 @@ public class SourceInfoTest {
 
     @Before
     public void beforeEach() {
-        offsetContext = MySqlOffsetContext.initial(new MySqlConnectorConfig(Configuration.create()
-                .with(CommonConnectorConfig.TOPIC_PREFIX, "server")
-                .build()));
+        offsetContext = MySqlOffsetContext.initial(
+            new MySqlConnectorConfig(
+                Configuration.create()
+                    .with(CommonConnectorConfig.TOPIC_PREFIX, "server")
+                    .build(),
+                new DefaultJdbcCredentialsProvider()
+            )
+        );
         source = offsetContext.getSource();
         inTxn = false;
         positionOfBeginEvent = 0L;
@@ -448,9 +454,14 @@ protected Map<String, String> offset(String gtidSet, long position, int row, boo
     }
 
     protected SourceInfo sourceWith(Map<String, String> offset) {
-        offsetContext = (MySqlOffsetContext) new MySqlOffsetContext.Loader(new MySqlConnectorConfig(Configuration.create()
+        offsetContext = (MySqlOffsetContext) new MySqlOffsetContext.Loader(
+            new MySqlConnectorConfig(
+                Configuration.create()
                 .with(CommonConnectorConfig.TOPIC_PREFIX, SERVER_NAME)
-                .build())).load(offset);
+                .build(),
+            new DefaultJdbcCredentialsProvider()
+            )
+        ).load(offset);
         source = offsetContext.getSource();
         source.databaseEvent("mysql");
         return source;
diff --git a/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/StreamingSourceIT.java b/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/StreamingSourceIT.java
index 1ed3f755021..31b3f3d01bf 100644
--- a/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/StreamingSourceIT.java
+++ b/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/StreamingSourceIT.java
@@ -153,7 +153,9 @@ private long getNumberOfSkippedEvents() {
     protected Configuration.Builder simpleConfig() {
         return DATABASE.defaultConfig()
                 .with(MySqlConnectorConfig.USER, "replicator")
+                .with("jdbc.creds.provider.user", "replicator")
                 .with(MySqlConnectorConfig.PASSWORD, "replpass")
+                .with("jdbc.creds.provider.password", "replpass")
                 .with(MySqlConnectorConfig.INCLUDE_SCHEMA_CHANGES, false)
                 .with(MySqlConnectorConfig.INCLUDE_SQL_QUERY, false)
                 .with(MySqlConnectorConfig.SNAPSHOT_MODE, MySqlConnectorConfig.SnapshotMode.NEVER);
@@ -509,7 +511,9 @@ public void testHeartbeatActionQueryExecuted() throws Exception {
 
         config = simpleConfig()
                 .with(MySqlConnectorConfig.USER, "snapper")
+                .with("jdbc.creds.provider.user", "snapper")
                 .with(MySqlConnectorConfig.PASSWORD, "snapperpass")
+                .with("jdbc.creds.provider.password", "snapperpass")
                 .with(AbstractTopicNamingStrategy.DEFAULT_HEARTBEAT_TOPIC_PREFIX, HEARTBEAT_TOPIC_PREFIX_VALUE)
                 .with(Heartbeat.HEARTBEAT_INTERVAL, "100")
                 .with(DatabaseHeartbeatImpl.HEARTBEAT_ACTION_QUERY_PROPERTY_NAME,
diff --git a/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/UniqueDatabase.java b/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/UniqueDatabase.java
index f943fa2696c..22f0567b462 100644
--- a/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/UniqueDatabase.java
+++ b/debezium-connector-mysql/src/test/java/io/debezium/connector/mysql/UniqueDatabase.java
@@ -194,7 +194,9 @@ public Configuration.Builder defaultJdbcConfigBuilder() {
                 .with(MySqlConnectorConfig.HOSTNAME, System.getProperty("database.hostname", "localhost"))
                 .with(MySqlConnectorConfig.PORT, System.getProperty("database.port", "3306"))
                 .with(MySqlConnectorConfig.USER, "snapper")
+                .with("jdbc.creds.provider.user", "snapper")
                 .with(MySqlConnectorConfig.PASSWORD, "snapperpass")
+                .with("jdbc.creds.provider.password", "snapperpass")
                 .with("driver.allowPublicKeyRetrieval", "true");
 
         String sslMode = System.getProperty("database.ssl.mode", "preferred");
diff --git a/debezium-connector-mysql/src/test/java/io/debezium/relational/history/KafkaSchemaHistoryTest.java b/debezium-connector-mysql/src/test/java/io/debezium/relational/history/KafkaSchemaHistoryTest.java
index 980309e48db..fe02a358d9d 100644
--- a/debezium-connector-mysql/src/test/java/io/debezium/relational/history/KafkaSchemaHistoryTest.java
+++ b/debezium-connector-mysql/src/test/java/io/debezium/relational/history/KafkaSchemaHistoryTest.java
@@ -14,6 +14,7 @@
 import java.util.Map;
 import java.util.concurrent.TimeoutException;
 
+import io.confluent.credentialproviders.DefaultJdbcCredentialsProvider;
 import org.apache.kafka.clients.consumer.ConsumerConfig;
 import org.apache.kafka.clients.producer.KafkaProducer;
 import org.apache.kafka.clients.producer.ProducerConfig;
@@ -91,7 +92,7 @@ public void beforeEach() throws Exception {
                 .with(CommonConnectorConfig.TOPIC_PREFIX, "dbserver1").build();
 
         position = new MySqlOffsetContext(false, true, new TransactionContext(), new MySqlReadOnlyIncrementalSnapshotContext<>(),
-                new SourceInfo(new MySqlConnectorConfig(config)));
+                new SourceInfo(new MySqlConnectorConfig(config, new DefaultJdbcCredentialsProvider())));
         offsets = Offsets.of(source, position);
 
         setLogPosition(0);
diff --git a/debezium-core/src/main/java/io/debezium/connector/common/RelationalBaseSourceConnector.java b/debezium-core/src/main/java/io/debezium/connector/common/RelationalBaseSourceConnector.java
index 6f73e905810..8fb6960b2db 100644
--- a/debezium-core/src/main/java/io/debezium/connector/common/RelationalBaseSourceConnector.java
+++ b/debezium-core/src/main/java/io/debezium/connector/common/RelationalBaseSourceConnector.java
@@ -43,7 +43,7 @@ public Config validate(Map<String, String> connectorConfigs) {
         final String passwordStringValue = config.getString(RelationalDatabaseConnectorConfig.PASSWORD);
 
         if (Strings.isNullOrEmpty(passwordStringValue)) {
-            LOGGER.debug("The connection password is empty");
+            LOGGER.info("The connection password is empty");
         }
 
         // If there are no errors on any of these ...
diff --git a/debezium-storage/debezium-storage-jdbc/src/test/java/io/debezium/storage/jdbc/JdbcOffsetBackingStoreIT.java b/debezium-storage/debezium-storage-jdbc/src/test/java/io/debezium/storage/jdbc/JdbcOffsetBackingStoreIT.java
index 717727efe1f..681449a9e17 100644
--- a/debezium-storage/debezium-storage-jdbc/src/test/java/io/debezium/storage/jdbc/JdbcOffsetBackingStoreIT.java
+++ b/debezium-storage/debezium-storage-jdbc/src/test/java/io/debezium/storage/jdbc/JdbcOffsetBackingStoreIT.java
@@ -118,7 +118,9 @@ private Configuration.Builder config(String jdbcUrl) {
                 .with(MySqlConnectorConfig.HOSTNAME, container.getHost())
                 .with(MySqlConnectorConfig.PORT, container.getMappedPort(PORT))
                 .with(MySqlConnectorConfig.USER, USER)
+                .with("jdbc.creds.provider.user", USER)
                 .with(MySqlConnectorConfig.PASSWORD, PASSWORD)
+                .with("jdbc.creds.provider.password", PASSWORD)
                 .with(MySqlConnectorConfig.DATABASE_INCLUDE_LIST, DBNAME)
                 .with(MySqlConnectorConfig.TABLE_INCLUDE_LIST, DBNAME + "." + TABLE_NAME)
                 .with(MySqlConnectorConfig.SERVER_ID, 18765)
diff --git a/debezium-storage/debezium-storage-jdbc/src/test/java/io/debezium/storage/jdbc/history/JdbcSchemaHistoryIT.java b/debezium-storage/debezium-storage-jdbc/src/test/java/io/debezium/storage/jdbc/history/JdbcSchemaHistoryIT.java
index 35db543f42e..14f54645aff 100644
--- a/debezium-storage/debezium-storage-jdbc/src/test/java/io/debezium/storage/jdbc/history/JdbcSchemaHistoryIT.java
+++ b/debezium-storage/debezium-storage-jdbc/src/test/java/io/debezium/storage/jdbc/history/JdbcSchemaHistoryIT.java
@@ -120,7 +120,9 @@ private Configuration.Builder config() throws IOException {
                 .with(MySqlConnectorConfig.HOSTNAME, container.getHost())
                 .with(MySqlConnectorConfig.PORT, container.getMappedPort(PORT))
                 .with(MySqlConnectorConfig.USER, USER)
+                .with("jdbc.creds.provider.user", USER)
                 .with(MySqlConnectorConfig.PASSWORD, PASSWORD)
+                .with("jdbc.creds.provider.password", PASSWORD)
                 .with(MySqlConnectorConfig.DATABASE_INCLUDE_LIST, DBNAME)
                 .with(MySqlConnectorConfig.TABLE_INCLUDE_LIST, DBNAME + "." + TABLE_NAME)
                 .with(MySqlConnectorConfig.SERVER_ID, 18765)
diff --git a/pom.xml b/pom.xml
index 58031f2a9fe..efd1402e611 100644
--- a/pom.xml
+++ b/pom.xml
@@ -124,7 +124,7 @@
         <!-- Database drivers, should align with databases -->
         <version.postgresql.driver>42.6.1</version.postgresql.driver>
         <version.mysql.driver>8.0.33</version.mysql.driver>
-        <version.mysql.binlog>0.30.0</version.mysql.binlog>
+        <version.mysql.binlog>0.40.2</version.mysql.binlog>
         <version.mongo.driver>4.7.1</version.mongo.driver>
         <version.sqlserver.driver>10.2.1.jre8</version.sqlserver.driver>
         <version.oracle.driver>21.6.0.0</version.oracle.driver>


Reviews:
user: login: akanimesh7
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-07T18:11:02Z
user: login: akanimesh7
body: - remove/re-purpose DEBUGIAMASSUMEROLE
- 
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-09T20:09:49Z
user: login: akanimesh7
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-10T02:51:06Z
user: login: sangeet259
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-10T05:14:27Z
user: login: akanimesh7
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-11T18:53:29Z

Review comments:
diff_hunk: @@ -0,0 +1,113 @@
+/*
+ * Copyright 2018 Confluent Inc.
+ *
+ * Licensed under the Confluent Community License (the "License"); you may not use
+ * this file except in compliance with the License.  You may obtain a copy of the
+ * License at
+ *
+ * http://www.confluent.io/confluent-community-license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+package io.debezium.connector.mysql;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.confluent.credentialproviders.DefaultJdbcCredentials;
+import io.confluent.credentialproviders.JdbcCredentials;
+import io.confluent.credentialproviders.JdbcCredentialsProvider;
+import io.confluent.credentialproviders.aws.AwsChainedAssumeRoleRdsCredsProvider;
+import io.debezium.config.Configuration;
+import io.debezium.connector.mysql.MySqlConnectorConfig.AuthenticationMethod;
+
+/**
+ * Utility class for handling JDBC credential providers
+ */
+public class JdbcCredentialsUtil {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(JdbcCredentialsUtil.class);
+
+    private static volatile JdbcCredentialsProvider PROVIDER_INSTANCE = null;
+
+    /**
+     * Get or create a credentials provider for the given configuration
+     * @param config the connector configuration
+     * @return the credentials provider, or null if none configured
+     */
+    public static synchronized JdbcCredentialsProvider getCredentialsProvider(Configuration config) {
+        
+        if (PROVIDER_INSTANCE != null) {
+             LOGGER.info("DEBUGIAMASSUMEROLE -Returning existing credentials provider");
+            return PROVIDER_INSTANCE;
+        }
+
+        AuthenticationMethod authMethod = MySqlConnectorConfig.getAuthenticationMethod(config);
+        LOGGER.info("DEBUGIAMASSUMEROLE -Authentication method: {}", authMethod);
+        if (authMethod == AuthenticationMethod.IAM_ROLES) {
+            LOGGER.info("Creating IAM role provider");
+            return createProvider(AwsChainedAssumeRoleRdsCredsProvider.class.getName(), config);
path: debezium-connector-mysql/src/main/java/io/debezium/connector/mysql/JdbcCredentialsUtil.java
user: login: akanimesh7
body: As discussed, let's use a config here and not hardcode
created_at: 2025-04-07T18:01:51Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,113 @@
+/*
+ * Copyright 2018 Confluent Inc.
+ *
+ * Licensed under the Confluent Community License (the "License"); you may not use
+ * this file except in compliance with the License.  You may obtain a copy of the
+ * License at
+ *
+ * http://www.confluent.io/confluent-community-license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OF ANY KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+package io.debezium.connector.mysql;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.confluent.credentialproviders.DefaultJdbcCredentials;
+import io.confluent.credentialproviders.JdbcCredentials;
+import io.confluent.credentialproviders.JdbcCredentialsProvider;
+import io.confluent.credentialproviders.aws.AwsChainedAssumeRoleRdsCredsProvider;
+import io.debezium.config.Configuration;
+import io.debezium.connector.mysql.MySqlConnectorConfig.AuthenticationMethod;
+
+/**
+ * Utility class for handling JDBC credential providers
+ */
+public class JdbcCredentialsUtil {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(JdbcCredentialsUtil.class);
+
+    private static volatile JdbcCredentialsProvider PROVIDER_INSTANCE = null;
+
+    /**
+     * Get or create a credentials provider for the given configuration
+     * @param config the connector configuration
+     * @return the credentials provider, or null if none configured
+     */
+    public static synchronized JdbcCredentialsProvider getCredentialsProvider(Configuration config) {
path: debezium-connector-mysql/src/main/java/io/debezium/connector/mysql/JdbcCredentialsUtil.java
user: login: akanimesh7
body: Used only in this file. Make it private.
created_at: 2025-04-07T18:03:09Z
author_association: MEMBER
diff_hunk: @@ -1113,11 +1151,19 @@ public int port() {
     }
 
     public String username() {
-        return config.getString(USER);
+        String username = credsProvider.getJdbcCreds().user();
+        if (username != null) {
path: debezium-connector-mysql/src/main/java/io/debezium/connector/mysql/MySqlConnectorConfig.java
user: login: akanimesh7
body: Only the line above this is sufficient ?
created_at: 2025-04-09T20:08:28Z
author_association: MEMBER
diff_hunk: @@ -1113,11 +1151,19 @@ public int port() {
     }
 
     public String username() {
-        return config.getString(USER);
+        String username = credsProvider.getJdbcCreds().user();
+        if (username != null) {
+            return username;
+        }
+        return config.getString(MySqlConnectorConfig.USER);
     }
 
     public String password() {
-        return config.getString(PASSWORD);
+        String password = credsProvider.getJdbcCreds().password();
+        if (password != null) {
path: debezium-connector-mysql/src/main/java/io/debezium/connector/mysql/MySqlConnectorConfig.java
user: login: akanimesh7
body: Only the line above this is sufficient ?
created_at: 2025-04-09T20:08:33Z
author_association: MEMBER
diff_hunk: @@ -25,7 +25,7 @@
         <skipITs>false</skipITs>
 
         <!-- Do not skip formatting source code by default -->
-        <format.skip>false</format.skip>
+        <format.skip>true</format.skip>
path: debezium-parent/pom.xml
user: login: akanimesh7
body: Added since, on runing maven commands, by default a lot of files got changed and hence relevant changes were lost.
created_at: 2025-04-09T20:09:18Z
author_association: MEMBER
diff_hunk: @@ -1014,6 +1029,29 @@ private static int validateEventDeserializationFailureHandlingModeNotSet(Configu
         return 0;
     }
 
+    private JdbcCredentialsProvider getCredentialsProvider(Configuration config){
+        String providerClass = config.getString(MySqlConnectorConfig.CREDENTIALS_PROVIDER_CLASS_NAME);
+        LOGGER.info("Credentials provider class: {}", providerClass);
path: debezium-connector-mysql/src/main/java/io/debezium/connector/mysql/MySqlConnectorConfig.java
user: login: akanimesh7
body: nit -- `LOGGER.info("Using credentials provider class: {}", providerClass);`
created_at: 2025-04-10T02:48:25Z
author_association: MEMBER
diff_hunk: @@ -1014,6 +1029,29 @@ private static int validateEventDeserializationFailureHandlingModeNotSet(Configu
         return 0;
     }
 
+    private JdbcCredentialsProvider getCredentialsProvider(Configuration config){
+        String providerClass = config.getString(MySqlConnectorConfig.CREDENTIALS_PROVIDER_CLASS_NAME);
+        LOGGER.info("Credentials provider class: {}", providerClass);
+        LOGGER.info("DEBUGIAMASSUMEROLE -Creating credentials provider: {}", providerClass);
+        try {
+            LOGGER.info("DEBUGIAMASSUMEROLE - Current config : {}", config.asMap());
+            JdbcCredentialsProvider provider = (JdbcCredentialsProvider) Class.forName(providerClass)
+                    .getDeclaredConstructor().newInstance();
+
+            LOGGER.info("Successfully created a new instance of credentials provider of type: {}", providerClass);
+            LOGGER.info("DEBUGIAMASSUMEROLE -Configuring credentials provider with config: {}", config.asMap());
+            provider.configure(config.asMap());
+            LOGGER.info("DEBUGIAMASSUMEROLE -Configured credentials provider: {}", provider);
+
+            return provider;
+        }
+        catch (Exception e) {
+            LOGGER.warn("Error initializing credentials provider {}: {}", providerClass, e.getMessage());
+            LOGGER.debug("Detailed provider initialization error", e);
+            return null;
path: debezium-connector-mysql/src/main/java/io/debezium/connector/mysql/MySqlConnectorConfig.java
user: login: akanimesh7
body: We should re-throw the exception here, since not having a provider is non-negotiable.

Since we are returning null, in future it might lead to irrelevant hard to debug NPEs when we use the value returned from this function.
created_at: 2025-04-10T02:50:23Z
author_association: MEMBER
diff_hunk: @@ -1014,6 +1029,29 @@ private static int validateEventDeserializationFailureHandlingModeNotSet(Configu
         return 0;
     }
 
+    private JdbcCredentialsProvider getCredentialsProvider(Configuration config){
+        String providerClass = config.getString(MySqlConnectorConfig.CREDENTIALS_PROVIDER_CLASS_NAME);
+        LOGGER.info("Credentials provider class: {}", providerClass);
+        LOGGER.info("DEBUGIAMASSUMEROLE -Creating credentials provider: {}", providerClass);
+        try {
+            LOGGER.info("DEBUGIAMASSUMEROLE - Current config : {}", config.asMap());
+            JdbcCredentialsProvider provider = (JdbcCredentialsProvider) Class.forName(providerClass)
+                    .getDeclaredConstructor().newInstance();
+
+            LOGGER.info("Successfully created a new instance of credentials provider of type: {}", providerClass);
+            LOGGER.info("DEBUGIAMASSUMEROLE -Configuring credentials provider with config: {}", config.asMap());
+            provider.configure(config.asMap());
+            LOGGER.info("DEBUGIAMASSUMEROLE -Configured credentials provider: {}", provider);
+
+            return provider;
+        }
+        catch (Exception e) {
+            LOGGER.warn("Error initializing credentials provider {}: {}", providerClass, e.getMessage());
+            LOGGER.debug("Detailed provider initialization error", e);
+            return null;
path: debezium-connector-mysql/src/main/java/io/debezium/connector/mysql/MySqlConnectorConfig.java
user: login: sangeet259
body: Done. Can you check ?
created_at: 2025-04-10T05:14:27Z
author_association: MEMBER

PR comments:
user: login: akanimesh7
created_at: 2025-04-10T02:45:46Z
body: @sangeet259 Please check and fix the failing tests
author_association: MEMBER
user: login: sangeet259
created_at: 2025-04-10T05:05:42Z
body: @akanimesh7 

> @sangeet259 Please check and fix the failing tests

![image](https://github.com/user-attachments/assets/7f66de68-0db9-4d6c-bcb9-862860df811a)
These checkstyle failures are in files not changed in this PR.


author_association: MEMBER
user: login: sangeet259
created_at: 2025-04-10T06:58:56Z
body: ```
Class name
io.debezium.connector.mysql.SourceInfoTest
io.debezium.DebeziumException Failed to initialize credentials provider: null
io.debezium.DebeziumException: Failed to initialize credentials provider: null
	at io.debezium.connector.mysql.MySqlConnectorConfig.getCredentialsProvider(MySqlConnectorConfig.java:1048)
	at io.debezium.connector.mysql.MySqlConnectorConfig.<init>(MySqlConnectorConfig.java:1008)
	at io.debezium.connector.mysql.SourceInfoTest.beforeEach(SourceInfoTest.java:53)
```


This failure will be addressed when we release the latest version of `credential-providers` because that contains the `DefaultCredentialProvider`.

author_association: MEMBER
user: login: sangeet259
created_at: 2025-04-11T12:43:44Z
body: All tests passing.

<img width="924" alt="image" src="https://github.com/user-attachments/assets/55dc44b6-f670-49bc-9fd3-9de373f81a99" />

author_association: MEMBER
user: login: akanimesh7
created_at: 2025-04-11T18:52:23Z
body: Thanks for iterating patiently @sangeet259 🚀 !!
Great work !
author_association: MEMBER