This document covers the creation and configuration of MySQL containers including Docker image selection, database credentials, and MySQL server configuration overrides.
Constructor Options:
MySQLContainer(String dockerImageName) - String-based image nameMySQLContainer(DockerImageName dockerImageName) - Type-safe image name (recommended)Configuration Methods (Fluent Interface, Return SELF):
withDatabaseName(String databaseName) - Set database name (default: "test")withUsername(String username) - Set username (default: "test")withPassword(String password) - Set password (default: "test")withConfigurationOverride(String configPath) - Mount custom my.cnf files from classpath directoryGetter Methods:
getDatabaseName(): String - Returns configured database namegetUsername(): String - Returns configured usernamegetPassword(): String - Returns configured passwordConstraints:
start()Create a new MySQL container instance with a specified Docker image.
/**
* Creates a MySQL container with the specified Docker image name string.
* The image name should follow Docker image naming conventions (e.g., "mysql:8.0" or "mysql:5.7.34").
*
* @param dockerImageName the Docker image name as a string (e.g., "mysql:8.0", "mysql:5.7.34")
* @throws IllegalArgumentException if dockerImageName is null or empty
*/
MySQLContainer(String dockerImageName);
/**
* Creates a MySQL container with the specified DockerImageName object.
* This is the recommended constructor as it provides type safety and validation.
*
* @param dockerImageName the Docker image name as a DockerImageName object
* @throws IllegalArgumentException if dockerImageName is null
*/
MySQLContainer(DockerImageName dockerImageName);Usage Example:
import org.testcontainers.containers.MySQLContainer;
import org.testcontainers.utility.DockerImageName;
// Using string image name
MySQLContainer<?> mysql1 = new MySQLContainer<>("mysql:8.0");
// Using DockerImageName (recommended)
MySQLContainer<?> mysql2 = new MySQLContainer<>(DockerImageName.parse("mysql:8.0.36"));Image Selection Guidelines:
Common Image Tags:
mysql:8.0 - Latest MySQL 8.0 (recommended)mysql:8.0.36 - Specific MySQL 8.0 patch versionmysql:5.7 - Latest MySQL 5.7mysql:5.7.34 - Specific MySQL 5.7 patch versionSet the name of the database to be created when the container starts.
/**
* Sets the name of the database to be created in the MySQL container.
* This database will be automatically created when the container starts.
* The database name cannot be changed after container creation.
*
* @param databaseName the database name (must be valid MySQL identifier)
* @return self for method chaining (SELF extends MySQLContainer<SELF>)
* @throws IllegalArgumentException if databaseName is null or empty
*/
SELF withDatabaseName(String databaseName);
/**
* Gets the configured database name.
* Returns the default value "test" if not explicitly set.
*
* @return the database name (default: "test")
*/
String getDatabaseName();Usage Example:
MySQLContainer<?> mysql = new MySQLContainer<>(DockerImageName.parse("mysql:8.0"))
.withDatabaseName("myapp_test");
mysql.start();
String dbName = mysql.getDatabaseName(); // "myapp_test"Important Notes:
Valid Database Names:
"testdb", "myapp_test", "integration_test_db""test db" (spaces), "test-db" (hyphens), "SELECT" (reserved keyword)Set the username for database connections.
/**
* Sets the username for database connections.
* If set to "root", special behavior applies for password handling.
* The username cannot be changed after container creation.
*
* @param username the database username (must be valid MySQL identifier)
* @return self for method chaining (SELF extends MySQLContainer<SELF>)
* @throws IllegalArgumentException if username is null or empty
*/
SELF withUsername(String username);
/**
* Gets the configured username.
* Returns the default value "test" if not explicitly set.
*
* @return the username (default: "test")
*/
String getUsername();Usage Example:
MySQLContainer<?> mysql = new MySQLContainer<>(DockerImageName.parse("mysql:8.0"))
.withUsername("myuser");
mysql.start();
String user = mysql.getUsername(); // "myuser"Important Notes:
MYSQL_ROOT_HOST to allow root login from any host (typically set to "%")ContainerLaunchExceptionRoot User Special Case:
// Root user with empty password requires MYSQL_ROOT_HOST
MySQLContainer<?> mysql = new MySQLContainer<>(DockerImageName.parse("mysql:8.0"))
.withUsername("root")
.withPassword("")
.withEnv("MYSQL_ROOT_HOST", "%"); // Required for root with empty passwordSet the password for database connections.
/**
* Sets the password for database connections.
* The password applies to both the configured user and the root user.
* The password cannot be changed after container creation.
*
* @param password the database password (can be empty string for root user only)
* @return self for method chaining (SELF extends MySQLContainer<SELF>)
* @throws IllegalArgumentException if password is null
*/
SELF withPassword(String password);
/**
* Gets the configured password.
* Returns the default value "test" if not explicitly set.
*
* @return the password (default: "test")
*/
String getPassword();Usage Example:
MySQLContainer<?> mysql = new MySQLContainer<>(DockerImageName.parse("mysql:8.0"))
.withUsername("myuser")
.withPassword("mypassword");
mysql.start();
String pwd = mysql.getPassword(); // "mypassword"Password Behavior:
MYSQL_ROOT_HOST environment variable is set)ContainerLaunchException at startupError Scenario: Empty Password with Non-Root User
// This will throw ContainerLaunchException
MySQLContainer<?> mysql = new MySQLContainer<>(DockerImageName.parse("mysql:8.0"))
.withUsername("testuser")
.withPassword(""); // Empty password not allowed for non-root user
mysql.start(); // Throws ContainerLaunchExceptionSolution:
// Use root user with MYSQL_ROOT_HOST
MySQLContainer<?> mysql = new MySQLContainer<>(DockerImageName.parse("mysql:8.0"))
.withUsername("root")
.withPassword("")
.withEnv("MYSQL_ROOT_HOST", "%");Mount custom MySQL configuration files (my.cnf) to override server settings.
/**
* Mounts custom MySQL configuration files from a classpath directory.
* All .cnf files in the specified directory will be mapped to /etc/mysql/conf.d
* in the container, allowing MySQL server settings to be overridden.
* Configuration is applied at container startup and cannot be changed without restart.
*
* @param configPath path to a directory on the classpath containing .cnf files
* @return self for method chaining (SELF extends MySQLContainer<SELF>)
* @throws IllegalArgumentException if configPath is null or empty
* @throws ContainerLaunchException if configPath does not exist on classpath or contains no .cnf files
*/
SELF withConfigurationOverride(String configPath);Usage Example:
// Assumes somepath/mysql_conf_override is a directory on the classpath
// containing .cnf files (e.g., custom.cnf)
MySQLContainer<?> mysql = new MySQLContainer<>(DockerImageName.parse("mysql:8.0"))
.withConfigurationOverride("somepath/mysql_conf_override");
mysql.start();Configuration Override Details:
src/test/resources/).cnf files in that directory will be mounted into the container/etc/mysql/conf.d/ within the containerExample my.cnf override file:
[mysqld]
innodb_max_undo_log_size=20000000
max_connections=500
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
innodb_buffer_pool_size=1GCommon Configuration Overrides:
max_connections - Maximum concurrent connectionsinnodb_buffer_pool_size - InnoDB buffer pool sizecharacter-set-server - Server character set (e.g., "utf8mb4")collation-server - Server collationinnodb_log_file_size - InnoDB log file sizemax_allowed_packet - Maximum packet sizewait_timeout - Connection timeoutinteractive_timeout - Interactive session timeoutimport org.testcontainers.containers.MySQLContainer;
import org.testcontainers.utility.DockerImageName;
try (MySQLContainer<?> mysql = new MySQLContainer<>(DockerImageName.parse("mysql:8.0.36"))
.withDatabaseName("integration_test_db")
.withUsername("testuser")
.withPassword("testpass123")
.withConfigurationOverride("mysql-config")) {
mysql.start();
// Container is ready with custom configuration
String jdbcUrl = mysql.getJdbcUrl();
// jdbc:mysql://localhost:xxxxx/integration_test_db?useSSL=false&allowPublicKeyRetrieval=true
}import org.testcontainers.containers.MySQLContainer;
import org.testcontainers.utility.DockerImageName;
// Using root user with empty password
try (MySQLContainer<?> mysql = new MySQLContainer<>(DockerImageName.parse("mysql:8.0"))
.withDatabaseName("testdb")
.withUsername("root")
.withPassword("")
.withEnv("MYSQL_ROOT_HOST", "%")) { // Required for root with empty password
mysql.start();
// Container is ready for root access with no password
}Root User Notes:
MYSQL_ROOT_HOST environment variable when using empty passwordMYSQL_ROOT_HOST to "%" to allow root login from any hostContainerLaunchException: Empty password with non-root user
// This will throw ContainerLaunchException
MySQLContainer<?> mysql = new MySQLContainer<>(DockerImageName.parse("mysql:8.0"))
.withUsername("testuser")
.withPassword(""); // Empty password not allowed for non-root user
mysql.start(); // Throws ContainerLaunchExceptionSolution:
// Use root user with MYSQL_ROOT_HOST
MySQLContainer<?> mysql = new MySQLContainer<>(DockerImageName.parse("mysql:8.0"))
.withUsername("root")
.withPassword("")
.withEnv("MYSQL_ROOT_HOST", "%");ContainerLaunchException: Invalid configuration override path
// This will throw ContainerLaunchException if path doesn't exist
MySQLContainer<?> mysql = new MySQLContainer<>(DockerImageName.parse("mysql:8.0"))
.withConfigurationOverride("nonexistent/path");
mysql.start(); // Throws ContainerLaunchExceptionSolution:
// Ensure path exists on classpath and contains .cnf files
// Place files in src/test/resources/mysql-config/
MySQLContainer<?> mysql = new MySQLContainer<>(DockerImageName.parse("mysql:8.0"))
.withConfigurationOverride("mysql-config"); // Valid classpath pathIllegalArgumentException: Null or empty parameters
// These will throw IllegalArgumentException
new MySQLContainer<>((String) null);
new MySQLContainer<>((DockerImageName) null);
mysql.withDatabaseName(null);
mysql.withUsername("");start() to catch errors early