Fix: Spring Boot Failed to Configure DataSource (DataSource Auto-Configuration Error)
Part of: Database Errors
Quick Answer
How to fix Spring Boot 'Failed to configure a DataSource' errors, missing URL property, driver class not found, connection refused, and how to correctly configure datasource properties for MySQL, PostgreSQL, and H2.
Failed to Configure a DataSource
I learned to read this one as Spring Boot finding a JDBC driver and then failing to finish the job, not as a generic startup crash. The auto-configuration walks a chain, detect the driver, read properties, pick a pool, validate the URL, connect, and any step can be the one that failed. When this bit me in production it was almost never the code; it was an unset SPRING_PROFILES_ACTIVE or a ${VAR} that never resolved.
Spring Boot fails to start with:
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource
could be configured.
Reason: Failed to determine a suitable driver classOr with a specific driver error:
Unable to determine Tomcat connection pool library.
java.lang.RuntimeException: Driver com.mysql.cj.jdbc.Driver claims to not accept jdbcUrlOr a connection error at startup:
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException:
Communications link failure — Last packet sent to the server was 0 ms ago.Or:
org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException:
Failed to determine a suitable driver classWhy Spring Boot Cannot Wire the DataSource
Spring Boot auto-configures a DataSource when it finds a database driver on the classpath. The auto-configuration requires at minimum a spring.datasource.url property. The auto-configuration is opt-out by design, adding spring-boot-starter-data-jpa or spring-boot-starter-jdbc triggers it even if you never wrote a @Configuration class for a DataSource.
The error message you see is usually the wrapper. The real cause is one layer deeper in the stack trace. Spring’s DataSourceAutoConfiguration walks through a chain: detect driver on classpath, resolve properties, pick a connection pool, validate the URL, attempt the first connection. Each step has a distinct failure mode, and the surface error reads the same.
Common root causes:
spring.datasource.urlis missing or empty, the most common cause. Spring Boot cannot guess the database URL and refuses to fall back to an embedded H2 when a real driver is on the classpath.- Database driver not on the classpath, the JDBC driver dependency is missing from
pom.xmlorbuild.gradle, or scoped asprovidedwhen it should beruntime. - Wrong JDBC URL format, the URL does not match the driver’s expected format. PostgreSQL wants
jdbc:postgresql://, MySQL wantsjdbc:mysql://, Oracle wantsjdbc:oracle:thin:@. - Database server is not running or not reachable, connection refused at startup. Common in Docker Compose when the app starts before the database is healthy.
- Wrong credentials, the username/password in properties does not match the database user, or the secret was not injected into the container.
- Spring Data JPA on classpath without a database configured, adding
spring-boot-starter-data-jpatriggers DataSource auto-configuration. If you do not need a database, exclude it. - Profile-specific properties not loaded,
application-prod.ymlwas not packaged into the jar, orSPRING_PROFILES_ACTIVEwas not set in the deployment environment.
Version History That Changes the Failure Mode
The exact wording and the fix depend heavily on the Spring Boot major version; a Boot 2 → Boot 3 migration is what trips most teams who copy a config that “always worked” on 2.7.
- Spring Boot 1.x (2014–2019, EOL). Used camelCase
spring.datasource.driverClassName, and Tomcat JDBC, not HikariCP, was the default pool. - Spring Boot 2.0 (Mar 2018). Default pool switched to HikariCP, and
driverClassNamewas renamed to kebab-casespring.datasource.driver-class-name. Oldtomcat-jdbctuning stopped applying silently. - Spring Boot 2.4 (Nov 2020). Property-loading order changed;
application-{profile}files override the base file more aggressively, and some${VAR:default}placeholders resolved in a different order than on 2.3. - Spring Boot 2.7 (May 2022). Last 2.x release;
javax.persistence.*/javax.sql.*imports still work here. - Spring Boot 3.0 (Nov 2022). The big break: Java 17 minimum, and every
javax.*import in Spring code moved tojakarta.*.javax.sql.DataSourceitself is unchanged (it lives in the JDK), but drivers compiled againstjavax.*(older Hibernate/Tomcat JDBC) silently fail to register and produce the sameFailed to determine a suitable driver classeven with a correct URL. The MySQL artifact also moved frommysql:mysql-connector-javatocom.mysql:mysql-connector-j. - Spring Boot 3.1 (May 2023). Added
spring.docker.compose.*(auto-start databases in local dev) and theConnectionDetailsAPI. - Spring Boot 3.2 (Nov 2023) / 3.3–3.4 (2024). Java 21 and virtual threads; later 3.x tightened bean post-processor ordering, breaking some custom
DataSourceconfigs that relied on the old lazy-init order.
If a project targets Java 8/11 and uses javax.persistence, it is Boot 2.x: copy Boot 3 snippets carefully, because the import lines and the MySQL artifact ID will not work.
Fix 1: Add the Required datasource Properties
The minimum required configuration:
# src/main/resources/application.properties
# PostgreSQL
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.username=myuser
spring.datasource.password=mypassword
spring.datasource.driver-class-name=org.postgresql.Driver
# MySQL
spring.datasource.url=jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC
spring.datasource.username=myuser
spring.datasource.password=mypassword
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# H2 in-memory (for development/testing)
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.h2.console.enabled=trueYAML format:
# src/main/resources/application.yml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/mydb
username: myuser
password: mypassword
driver-class-name: org.postgresql.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialectNote:
driver-class-nameis optional when the JDBC URL prefix matches a known driver on the classpath. Spring Boot infers the driver fromjdbc:postgresql://→ PostgreSQL driver,jdbc:mysql://→ MySQL driver, etc. Specify it explicitly if auto-detection fails.
Fix 2: Add the JDBC Driver Dependency
If the driver is not on the classpath, Spring Boot cannot connect regardless of properties.
Maven, add to pom.xml:
<!-- PostgreSQL -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<!-- MySQL -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- H2 (in-memory, for tests) -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>Gradle, add to build.gradle:
dependencies {
// PostgreSQL
runtimeOnly 'org.postgresql:postgresql'
// MySQL
runtimeOnly 'com.mysql:mysql-connector-j'
// H2 (tests only)
testRuntimeOnly 'com.h2database:h2'
}After adding the dependency, run:
# Maven
mvn clean install
# Gradle
./gradlew dependencies | grep -i postgresqlFix 3: Fix JDBC URL Format
Each database requires a specific URL format:
PostgreSQL:
# Standard
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
# With SSL
spring.datasource.url=jdbc:postgresql://host:5432/mydb?sslmode=require
# Cloud SQL (GCP)
spring.datasource.url=jdbc:postgresql:///mydb?cloudSqlInstance=project:region:instance&socketFactory=com.google.cloud.sql.postgres.SocketFactoryMySQL:
# MySQL 8.x — use CJ driver
spring.datasource.url=jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
# Common parameters to add when you see connection errors:
# useSSL=false — disable SSL for local dev
# serverTimezone=UTC — required by MySQL Connector/J 8.0+
# allowPublicKeyRetrieval=true — required for some MySQL 8 auth configurationsSQL Server:
spring.datasource.url=jdbc:sqlserver://localhost:1433;databaseName=mydb;encrypt=false
spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriverH2 (file-based instead of in-memory):
spring.datasource.url=jdbc:h2:file:./data/mydb;AUTO_SERVER=TRUEFix 4: Use Environment Variables for Credentials
Hardcoding credentials in application.properties is a security risk. Use environment variables or a secrets manager:
# application.properties — references environment variables
spring.datasource.url=${DATABASE_URL}
spring.datasource.username=${DATABASE_USERNAME}
spring.datasource.password=${DATABASE_PASSWORD}# Set environment variables before running
export DATABASE_URL=jdbc:postgresql://localhost:5432/mydb
export DATABASE_USERNAME=myuser
export DATABASE_PASSWORD=secret
java -jar app.jarSpring Boot also reads from .env via system properties at runtime:
java -DDATABASE_URL=jdbc:postgresql://localhost:5432/mydb -jar app.jarFor different environments, use Spring profiles:
# application.properties (defaults)
spring.profiles.active=dev
# application-dev.properties
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driver-class-name=org.h2.Driver
# application-prod.properties
spring.datasource.url=${DATABASE_URL}
spring.datasource.username=${DATABASE_USERNAME}
spring.datasource.password=${DATABASE_PASSWORD}# Activate a profile at runtime
java -Dspring.profiles.active=prod -jar app.jar
# Or:
SPRING_PROFILES_ACTIVE=prod java -jar app.jarFix 5: Exclude DataSource Auto-Configuration When Not Needed
If you added spring-boot-starter-data-jpa or spring-boot-starter-jdbc but do not actually need a database (e.g., you use MongoDB only), exclude the DataSource auto-configuration:
// Main application class
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
HibernateJpaAutoConfiguration.class
})
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}Or via properties:
spring.autoconfigure.exclude=\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfigurationFix 6: Fix Connection Pool Configuration
Spring Boot uses HikariCP by default. Connection pool exhaustion causes startup failures or slow queries at runtime:
# HikariCP connection pool settings
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.connection-timeout=30000 # 30 seconds
spring.datasource.hikari.idle-timeout=600000 # 10 minutes
spring.datasource.hikari.max-lifetime=1800000 # 30 minutes
spring.datasource.hikari.connection-test-query=SELECT 1
# For PostgreSQL — use pgBouncer URL with transaction mode
# spring.datasource.hikari.connection-init-sql=SET search_path TO myschemaDiagnose pool exhaustion:
# Enable HikariCP logging
logging.level.com.zaxxer.hikari=DEBUG
logging.level.com.zaxxer.hikari.HikariConfig=DEBUGFix 7: Test the Connection Outside Spring Boot
If Spring Boot cannot connect, verify the connection parameters are correct first:
# Test PostgreSQL connection with psql
psql -h localhost -p 5432 -U myuser -d mydb
# Test MySQL connection
mysql -h localhost -P 3306 -u myuser -pmypassword mydb
# Test if the port is reachable
nc -zv localhost 5432
telnet localhost 5432Simple Java connection test (without Spring):
import java.sql.Connection;
import java.sql.DriverManager;
public class TestConnection {
public static void main(String[] args) throws Exception {
String url = "jdbc:postgresql://localhost:5432/mydb";
String user = "myuser";
String password = "mypassword";
try (Connection conn = DriverManager.getConnection(url, user, password)) {
System.out.println("Connected: " + conn.getMetaData().getDatabaseProductName());
}
}
}Fix 8: Activate the Correct Profile
A very common cause is that the datasource properties live in a profile-specific file (application-dev.properties, application-prod.yml) that never gets activated, so Spring Boot sees no spring.datasource.url at all. Activate the profile that holds the config:
# As a program argument
java -jar myapp.jar --spring.profiles.active=dev
# Or via environment variable (the form to use in containers)
export SPRING_PROFILES_ACTIVE=dev
java -jar myapp.jarIn a single YAML file you can keep all profiles together using document separators and spring.config.activate.on-profile:
# application.yml
spring:
config:
activate:
on-profile: dev
datasource:
url: jdbc:postgresql://localhost:5432/mydb_dev
username: dev_user
password: dev_pass
---
spring:
config:
activate:
on-profile: prod
datasource:
url: ${POSTGRES_URL}
username: ${POSTGRES_USER}
password: ${POSTGRES_PASSWORD}The classic production failure here is packaging the jar but forgetting to set SPRING_PROFILES_ACTIVE in the deployment, so the prod block never activates and startup dies with this error.
Fix 9: Use H2 in Tests but a Real Database in Production
If you want a real database in dev/prod but an in-memory H2 for tests, override the datasource in the test resources only, rather than disabling the real config:
# src/test/resources/application.properties — overrides main for tests
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2DialectKeep H2 scoped to test so it never ships in the production jar:
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>Fix 10: Configure Multiple DataSources
Spring Boot only auto-configures one DataSource. The moment you declare a second DataSource bean, auto-configuration backs off and you must wire each one explicitly:
@Configuration
public class DataSourceConfig {
@Bean
@Primary
@ConfigurationProperties("spring.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
}spring.datasource.primary.url=jdbc:postgresql://localhost:5432/primary_db
spring.datasource.primary.username=user1
spring.datasource.primary.password=pass1
spring.datasource.secondary.url=jdbc:postgresql://localhost:5432/secondary_db
spring.datasource.secondary.username=user2
spring.datasource.secondary.password=pass2Two things bite people here. First, the spring.datasource.primary.* keys do nothing on their own; they only bind because of the @ConfigurationProperties("spring.datasource.primary") on the bean. Without the explicit @Bean methods, Spring Boot ignores both prefixes and still looks for the flat spring.datasource.url. Second, you must point JPA at each DataSource with @EnableJpaRepositories(basePackages = "...", entityManagerFactoryRef = "...", transactionManagerRef = "..."); otherwise every repository targets the primary DataSource and you get cryptic “table does not exist” errors at runtime instead of a clean startup failure.
In Production: Incident Lens
This is a startup-failure incident, not a runtime degradation. The blast radius is 100 percent of new pods or instances rolling out, they never reach Ready state, so no traffic is served from the new revision. If you are mid-deploy and the old revision is still healthy, the old pods keep serving until they get terminated. If you are doing a blue/green or canary deploy, the canary pods fail their startup probe and the rollout stalls. If you are doing a rolling deploy without proper readiness gating, you can drain old healthy pods before the new ones come up, that is when the outage becomes user-visible.
Detection signals to wire up:
- Spring Boot Actuator
/actuator/healthreturning DOWN with componentdb(Hikari reports pool status here) - Kubernetes
startupProbefailures incrementing on the new pod - Container restart count climbing without ever reaching Ready
- Log pattern
APPLICATION FAILED TO STARTmatched in your log aggregator - Metrics:
hikaricp_connections_activeflat at zero after pod start
Recovery playbook:
- Stop the rollout,
kubectl rollout pause deployment/<name>or pause the pipeline. Do not let more pods cycle through the failure. - Roll back to last known good,
kubectl rollout undo deployment/<name>restores the previous ReplicaSet. This buys you time. - Diff the configuration, compare the failing revision’s ConfigMap / env vars / Secret against the previous one. The bad value is almost always in
SPRING_DATASOURCE_URL,SPRING_DATASOURCE_USERNAME, orSPRING_DATASOURCE_PASSWORD. - Verify the secret was actually injected,
kubectl execinto a fresh debug pod with the same service account and print the env. Missing env is a very common root cause when secrets are sourced from external systems. - Test connectivity from the pod network,
nc -zv db-host 5432. If this fails, the issue is networking or DNS, not Spring.
Prevention:
- Move credentials into HashiCorp Vault, AWS Secrets Manager, or GCP Secret Manager. Inject via the platform’s secret-mount mechanism so rotation does not require a redeploy.
- Make Kubernetes
readinessProbehit/actuator/health/readinessso pods do not receive traffic until the DataSource is actually live. - Gate deploys on a smoke test that hits a
/healthzendpoint that exercises a real query (not just a pool ping). - Add a contract test that boots the application context against a Testcontainers Postgres in CI, this catches missing properties before they reach production.
DataSource Failures With Subtler Causes
Check the full stack trace. The Failed to configure a DataSource message is often a wrapper, the root cause is further down:
Caused by: java.net.ConnectException: Connection refused
at java.net.PlainSocketImpl.socketConnect(Native Method)Connection refused means the database server is not running or not listening on the expected port. Check:
# PostgreSQL
sudo systemctl status postgresql
sudo -u postgres psql -c '\l'
# MySQL
sudo systemctl status mysql
mysql -u root -pCheck if the database exists. Spring Boot connects to a specific database, if the database does not exist, the connection fails even if the server is running:
-- PostgreSQL
CREATE DATABASE mydb;
GRANT ALL PRIVILEGES ON DATABASE mydb TO myuser;
-- MySQL
CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
GRANT ALL PRIVILEGES ON mydb.* TO 'myuser'@'localhost';
FLUSH PRIVILEGES;Check Flyway or Liquibase migration failures. If you use database migration tools, a failed migration prevents Spring Boot from starting. Check the migration logs and the flyway_schema_history table for failed entries. A migration that ran partially and then crashed leaves the schema in a state where the next attempt cannot proceed, repair with mvn flyway:repair or by manually clearing the bad row.
Check for SSL handshake failures. Managed databases (RDS, Cloud SQL, Azure Database) often require SSL by default. If your URL omits sslmode=require or your CA bundle is missing, you get SSLException: PKIX path building failed wrapped inside the DataSource error. Add the cloud provider’s certificate to the JVM trust store, or set sslmode=require plus sslrootcert=... in the URL.
Check for IPv4 vs IPv6 binding mismatches. A database listening on 127.0.0.1 only is unreachable from a container that resolves localhost to ::1. Either bind the database to 0.0.0.0 (carefully, only for dev) or use the explicit IPv4 address in the JDBC URL.
Check the Hikari pool initialization order. When spring.datasource.hikari.initialization-fail-timeout is set to its default of 1ms, Hikari attempts a connection at startup and fails the context if the database is not immediately reachable. Setting it to -1 makes Hikari lazy (fail at first use instead of startup), sometimes appropriate for batch jobs but rarely for web services.
For related Spring Boot and Java database issues, see Fix: Spring Boot WhiteLabel Error Page, Fix: MySQL Access Denied for User, Fix: PostgreSQL Connection Refused, and Fix: Spring Data JPA Query Not Working.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: Spring Data JPA Query Not Working — @Query, Derived Methods, and N+1 Problems
How to fix Spring Data JPA query issues — JPQL vs native SQL, derived method naming, @Modifying for updates, pagination, projections, and LazyInitializationException.
Fix: Spring Boot @Transactional Not Rolling Back — Transaction Committed Despite Exception
How to fix Spring @Transactional not rolling back — checked vs unchecked exceptions, self-invocation proxy bypass, rollbackFor, transaction propagation, and nested transactions.
Fix: Spring Boot @Cacheable Not Working — Cache Miss Every Time or Stale Data
How to fix Spring Boot @Cacheable issues — @EnableCaching missing, self-invocation bypass, key generation, TTL configuration, cache eviction, and Caffeine vs Redis setup.
Fix: Hibernate LazyInitializationException — Could Not Initialize Proxy
How to fix Hibernate LazyInitializationException — loading lazy associations outside an active session, fetch join, @Transactional scope, DTO projection, and Open Session in View.