This document covers customizing JDBC URL parameters and configuring container startup and connection timeouts.
URL Parameter Methods (Fluent Interface, Return SELF):
withUrlParam(String paramName, String paramValue) - Add custom JDBC URL parameterTimeout Methods (Fluent Interface, Return SELF):
withStartupTimeoutSeconds(int startupTimeoutSeconds) - Set startup timeout (default: 120 seconds)withConnectTimeoutSeconds(int connectTimeoutSeconds) - Set connection timeout (default: 120 seconds)Automatic URL Parameters:
useSSL=false - Added automatically if not presentallowPublicKeyRetrieval=true - Added automatically if not presentConstraints:
start()Add custom parameters to the JDBC connection URL.
/**
* Adds a custom parameter to the JDBC connection URL.
* Parameters are appended as query string parameters (e.g., ?param1=value1¶m2=value2).
*
* Can be called multiple times to add multiple parameters.
* Parameters are automatically URL-encoded if necessary.
* If a parameter with the same name is added multiple times, the last value is used.
*
* @param paramName the parameter name (must not be null or empty)
* @param paramValue the parameter value (can be null or empty)
* @return self for method chaining (SELF extends MySQLContainer<SELF>)
* @throws IllegalArgumentException if paramName is null or empty
*/
SELF withUrlParam(String paramName, String paramValue);Usage Example:
import org.testcontainers.containers.MySQLContainer;
import org.testcontainers.utility.DockerImageName;
MySQLContainer<?> mysql = new MySQLContainer<>(DockerImageName.parse("mysql:8.0"))
.withUrlParam("serverTimezone", "UTC")
.withUrlParam("allowMultiQueries", "true")
.withUrlParam("useUnicode", "true")
.withUrlParam("characterEncoding", "UTF-8");
mysql.start();
String jdbcUrl = mysql.getJdbcUrl();
// jdbc:mysql://localhost:xxxxx/test?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8Here are commonly used MySQL JDBC URL parameters:
Connection Behavior:
serverTimezone - Server timezone (e.g., "UTC", "America/New_York")useSSL - Enable/disable SSL (automatically set to false by container)allowPublicKeyRetrieval - Allow public key retrieval (automatically set to true by container)autoReconnect - Automatically reconnect on connection loss (e.g., "true")Query Execution:
allowMultiQueries - Allow multiple queries in one statement (e.g., "true")rewriteBatchedStatements - Optimize batch inserts (e.g., "true")Character Encoding:
useUnicode - Enable Unicode support (e.g., "true")characterEncoding - Character encoding (e.g., "UTF-8", "utf8mb4")Performance:
cachePrepStmts - Enable prepared statement caching (e.g., "true")prepStmtCacheSize - Prepared statement cache size (e.g., "250")prepStmtCacheSqlLimit - Max SQL length for caching (e.g., "2048")useServerPrepStmts - Use server-side prepared statements (e.g., "true")elideSetAutoCommits - Reduce round trips (e.g., "true")useLocalSessionState - Use local session state (e.g., "true")import org.testcontainers.containers.MySQLContainer;
import org.testcontainers.utility.DockerImageName;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;
import java.time.ZonedDateTime;
import java.time.ZoneId;
MySQLContainer<?> mysql = new MySQLContainer<>(DockerImageName.parse("mysql:8.0"))
.withUrlParam("serverTimezone", "Europe/London")
.withEnv("TZ", "Europe/London"); // Set container timezone
mysql.start();
try (Connection conn = mysql.createConnection("")) {
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT NOW()");
rs.next();
// Date/time returned in Europe/London timezone
}import org.testcontainers.containers.MySQLContainer;
import org.testcontainers.utility.DockerImageName;
import java.sql.Connection;
import java.sql.Statement;
MySQLContainer<?> mysql = new MySQLContainer<>(DockerImageName.parse("mysql:8.0"))
.withUrlParam("allowMultiQueries", "true");
mysql.start();
try (Connection conn = mysql.createConnection("")) {
Statement stmt = conn.createStatement();
// Execute multiple statements in one call
String multiQuery = """
DROP TABLE IF EXISTS test;
CREATE TABLE test (id INT, name VARCHAR(50));
INSERT INTO test VALUES (1, 'Alice'), (2, 'Bob');
""";
stmt.execute(multiQuery);
}Configure how long to wait for the container to start, including image pull time.
/**
* Sets the maximum time to wait for the container to start, including Docker image
* pull time if the image is not already present locally.
*
* The timeout includes:
* - Docker image pull time (if image not cached)
* - Container creation time
* - Container startup time
* - Database initialization time
* - Initialization script execution time
* - Liveness check time
*
* Default: 120 seconds
*
* @param startupTimeoutSeconds timeout in seconds (must be positive)
* @return self for method chaining (SELF extends MySQLContainer<SELF>)
* @throws IllegalArgumentException if startupTimeoutSeconds is not positive
*/
SELF withStartupTimeoutSeconds(int startupTimeoutSeconds);Usage Example:
import org.testcontainers.containers.MySQLContainer;
import org.testcontainers.utility.DockerImageName;
MySQLContainer<?> mysql = new MySQLContainer<>(DockerImageName.parse("mysql:8.0"))
.withStartupTimeoutSeconds(180); // Wait up to 3 minutes
mysql.start();
// Will wait up to 180 seconds for container to become readyWhen to Increase Startup Timeout:
Configure how long to wait for the database to become ready and accept connections.
/**
* Sets the maximum time to wait for the database to start and establish an initial
* connection after the container is running.
*
* This timeout applies to the connection establishment phase, which includes:
* - Database server readiness check
* - Initial connection attempt
* - Authentication
*
* Default: 120 seconds
*
* @param connectTimeoutSeconds timeout in seconds (must be positive)
* @return self for method chaining (SELF extends MySQLContainer<SELF>)
* @throws IllegalArgumentException if connectTimeoutSeconds is not positive
*/
SELF withConnectTimeoutSeconds(int connectTimeoutSeconds);Usage Example:
import org.testcontainers.containers.MySQLContainer;
import org.testcontainers.utility.DockerImageName;
MySQLContainer<?> mysql = new MySQLContainer<>(DockerImageName.parse("mysql:8.0"))
.withConnectTimeoutSeconds(60); // Wait up to 1 minute for connection
mysql.start();
// Will attempt to connect for up to 60 secondsWhen to Increase Connection Timeout:
import org.testcontainers.containers.MySQLContainer;
import org.testcontainers.utility.DockerImageName;
MySQLContainer<?> mysql = new MySQLContainer<>(DockerImageName.parse("mysql:8.0"))
.withDatabaseName("myapp_test")
.withUsername("testuser")
.withPassword("testpass")
// JDBC URL parameters
.withUrlParam("serverTimezone", "UTC")
.withUrlParam("allowMultiQueries", "true")
.withUrlParam("useUnicode", "true")
.withUrlParam("characterEncoding", "UTF-8")
.withUrlParam("cachePrepStmts", "true")
.withUrlParam("prepStmtCacheSize", "250")
// Timeout configuration
.withStartupTimeoutSeconds(180)
.withConnectTimeoutSeconds(90)
// Initialization
.withInitScript("schema.sql");
mysql.start();
String jdbcUrl = mysql.getJdbcUrl();
// All URL parameters are included in the JDBC URLConfigure JDBC URL parameters for optimal performance in tests:
import org.testcontainers.containers.MySQLContainer;
import org.testcontainers.utility.DockerImageName;
MySQLContainer<?> mysql = new MySQLContainer<>(DockerImageName.parse("mysql:8.0"))
.withDatabaseName("perftest")
// Enable prepared statement caching
.withUrlParam("cachePrepStmts", "true")
.withUrlParam("prepStmtCacheSize", "250")
.withUrlParam("prepStmtCacheSqlLimit", "2048")
// Optimize batch operations
.withUrlParam("rewriteBatchedStatements", "true")
// Enable server-side prepared statements
.withUrlParam("useServerPrepStmts", "true")
// Reduce round trips
.withUrlParam("elideSetAutoCommits", "true")
.withUrlParam("useLocalSessionState", "true")
.withInitScript("schema.sql");
mysql.start();The MySQL module automatically adds these parameters to the JDBC URL if not already present:
These parameters are added automatically and do not need to be specified via withUrlParam(). However, if you explicitly set them via withUrlParam(), your values will take precedence.
Example:
MySQLContainer<?> mysql = new MySQLContainer<>(DockerImageName.parse("mysql:8.0"));
mysql.start();
String url = mysql.getJdbcUrl();
// url includes "?useSSL=false&allowPublicKeyRetrieval=true" automaticallyTo enable SSL (override the automatic parameter):
MySQLContainer<?> mysql = new MySQLContainer<>(DockerImageName.parse("mysql:8.0"))
.withUrlParam("useSSL", "true")
.withUrlParam("trustCertificateKeyStoreUrl", "file:/path/to/keystore")
.withUrlParam("trustCertificateKeyStorePassword", "password");
mysql.start();
// SSL is now enabled with custom certificate configurationFor CI/CD environments with limited resources or slow networks:
import org.testcontainers.containers.MySQLContainer;
import org.testcontainers.utility.DockerImageName;
boolean isCiEnvironment = System.getenv("CI") != null;
MySQLContainer<?> mysql = new MySQLContainer<>(DockerImageName.parse("mysql:8.0"))
.withDatabaseName("ci_test");
if (isCiEnvironment) {
mysql
.withStartupTimeoutSeconds(300) // 5 minutes for slow CI runners
.withConnectTimeoutSeconds(120); // 2 minutes for connection
}
mysql.start();If you encounter timeout-related exceptions:
IllegalStateException: "Container is started, but cannot be accessed"
This typically means the connection timeout was reached. Try:
Increase connection timeout:
.withConnectTimeoutSeconds(180)Check container logs for errors:
.withLogConsumer(new Slf4jLogConsumer(logger))Verify Docker resources (memory, CPU)
Check network connectivity
Ensure no firewall blocks container ports
Container startup timeout
If the container fails to start within the startup timeout:
Increase startup timeout:
.withStartupTimeoutSeconds(300)Check Docker image pull progress (slow network)
Reduce initialization script size or complexity
Verify sufficient Docker resources
Check for port conflicts (rare, as ports are dynamically assigned)
withUrlParam("serverTimezone", "UTC") for consistent behaviorrewriteBatchedStatements for bulk insertsuseSSL=false and allowPublicKeyRetrieval=true unless necessarystart()IllegalStateException for timeout scenarios