Fix: Spring Boot Failed to Configure a DataSource
Part of: Database Errors
Quick Answer
How to fix 'Failed to configure a DataSource: url attribute is not specified' in Spring Boot — adding database properties, excluding DataSource auto-configuration, H2 vs production DB setup, and multi-datasource configuration.
The Error
Spring Boot fails to start with:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded
datasource could be configured.
Reason: Failed to determine a suitable driver class
Action:
Consider the following:
If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
If you have database settings to be auto-configured by Spring Boot, perhaps you forgot to
specify the database connection details?Or:
APPLICATION FAILED TO START
Description:
Cannot determine embedded database driver class for database type NONE
Action:
If you want an embedded database, please put it on the classpath.Or after adding database properties, a different error:
org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException:
Failed to determine a suitable driver classWhy This Happens
Spring Boot’s auto-configuration detects spring-data-jpa, spring-jdbc, or any JPA/database dependency on the classpath and automatically tries to configure a DataSource. If no database URL is provided, it looks for an embedded database (H2, HSQL, Derby) on the classpath. If it finds neither, the DataSourceAutoConfiguration @Conditional chain fails and the application context refuses to refresh.
The auto-configuration is opinionated by design: pulling in spring-boot-starter-data-jpa is interpreted as “I want a database.” The framework then either picks up an explicit URL from properties, or falls back to an embedded driver. There is no third option — Spring Boot will not silently start without a DataSource once the JPA starter is on the classpath. That is why the same project that builds fine on a developer laptop (where H2 is on the test classpath) fails the moment you deploy a runtime JAR built with -Pprod that strips H2 out.
The error also surfaces during partial migrations. Teams that add MongoDB, Redis, or Elasticsearch but leave a stray JPA dependency in a parent POM trigger the same failure: Spring Boot sees JPA, tries to wire a DataSource, and dies even though the actual application never touches a relational database.
- Database dependency added without connection properties — you added
spring-boot-starter-data-jpabut didn’t configurespring.datasource.urlinapplication.properties. - Wrong property file loaded — your database properties are in
application-dev.propertiesbut thedevprofile isn’t activated, so Spring Boot readsapplication.propertieswhich has no database config. - H2 not on classpath for tests — you use a real database in production but want H2 for tests. H2 isn’t added as a test dependency.
- Driver class not found — the database driver JAR isn’t on the classpath (missing Maven/Gradle dependency).
- Placeholder values not replaced —
spring.datasource.url=${DB_URL}but theDB_URLenvironment variable isn’t set, leaving the URL as the literal${DB_URL}string.
Version History That Changes the Failure Mode
The exact wording of this error and the fix you need depend heavily on the Spring Boot major version. A migration from Boot 2 to Boot 3 has tripped many teams who copied a config that “always worked” on 2.7.
Spring Boot 1.x (Apr 2014 – Aug 2019). Used spring.datasource.url and spring.datasource.driverClassName (camelCase). Tomcat JDBC was the default pool, not HikariCP. Auto-configuration was less aggressive — projects without JPA could start without a DataSource without explicit exclusions. End-of-life since August 2019.
Spring Boot 2.0 (March 2018). Switched the default connection pool to HikariCP. Renamed spring.datasource.driverClassName to spring.datasource.driver-class-name (kebab-case). Added spring.datasource.hikari.* properties. Old tomcat-jdbc configurations stopped applying silently.
Spring Boot 2.4 (November 2020). Changed the property-loading order. application-{profile}.properties files now override application.properties more aggressively, and spring.config.import was introduced. Some ${VAR:default} placeholders that worked on 2.3 stopped resolving in the expected order.
Spring Boot 2.5 (May 2021). Deprecated spring.profiles.active inside profile-specific files. Using spring.profiles.active=prod inside application-dev.properties started printing warnings and was removed entirely in 3.0.
Spring Boot 2.7 (May 2022). Last 2.x release. Final chance to fix configuration before the Jakarta jump. Many javax.persistence.* and javax.sql.* imports still worked here.
Spring Boot 3.0 (November 2022). The big break. Java 17 became the minimum. Every javax.* import inside Spring code moved to jakarta.* (Jakarta EE 9 namespace). javax.sql.DataSource is unchanged because it lives in the JDK, but javax.persistence.Entity became jakarta.persistence.Entity. Drivers compiled against javax.* (older Hibernate, older Tomcat JDBC) silently fail to register, producing the same Failed to determine a suitable driver class even when the JDBC URL is correct. The MySQL group ID also moved from mysql:mysql-connector-java to com.mysql:mysql-connector-j.
Spring Boot 3.1 (May 2023). Introduced spring.docker.compose.* for auto-starting databases during local development and the ConnectionDetails API for cleaner cloud-bound config.
Spring Boot 3.2 (November 2023). Java 21 supported, virtual threads available via spring.threads.virtual.enabled=true. @ConditionalOnProperty evolved to support matchIfMissing more predictably.
Spring Boot 3.3 / 3.4 (2024). Tightened bean post-processor ordering; some custom DataSource configurations that worked through Boot 2 broke because they relied on lazy initialization order that no longer holds.
If you are looking at a project that targets Java 8 or 11 and uses javax.persistence, you are on Boot 2.x — copy Boot 3 config snippets carefully because the import lines and the MySQL artifact ID will not work.
Fix 1: Add Database Connection Properties
Add the required properties to 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
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialectMySQL:
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
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8DialectH2 (in-memory, for development/testing):
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=create-drop
spring.h2.console.enabled=true # Enable H2 browser console at /h2-consoleFix 2: Add the Database Driver Dependency
Without the JDBC driver on the classpath, Spring Boot can’t connect even with correct properties.
Maven — 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 (for tests or embedded dev) -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope> <!-- or scope: test for test-only -->
</dependency>Gradle — build.gradle:
dependencies {
// PostgreSQL
runtimeOnly 'org.postgresql:postgresql'
// MySQL
runtimeOnly 'com.mysql:mysql-connector-j'
// H2 (test only)
testRuntimeOnly 'com.h2database:h2'
}After adding dependencies, reload/reimport your Maven or Gradle project. IDEs like IntelliJ and VS Code cache the resolved classpath; if you skip the reload step, the IDE still reports the old classpath and the next build fails with the same Failed to determine a suitable driver class error even though the dependency is in pom.xml. Force a clean build with mvn clean package -DskipTests or ./gradlew clean build -x test to verify the JAR is actually being resolved.
Fix 3: Activate the Correct Profile
If database properties are in a profile-specific file (e.g., application-dev.properties), activate the profile:
application.properties (base):
# No database config here — it's profile-specific
spring.application.name=myappapplication-dev.properties:
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb_dev
spring.datasource.username=dev_user
spring.datasource.password=dev_passapplication-prod.properties:
spring.datasource.url=${POSTGRES_URL}
spring.datasource.username=${POSTGRES_USER}
spring.datasource.password=${POSTGRES_PASSWORD}Activate the profile:
# Run with dev profile
java -jar myapp.jar --spring.profiles.active=dev
# Or via environment variable
export SPRING_PROFILES_ACTIVE=dev
java -jar myapp.jar
# In application.properties (always activate dev locally)
spring.profiles.active=devIn IntelliJ: Run/Debug Configurations → Active profiles → dev
Pro Tip: Use YAML format for cleaner multi-profile configuration in a single file:
# application.yml spring: profiles: active: dev --- 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}
Fix 4: Exclude DataSource Auto-Configuration
If your application doesn’t need a database at all (you added JPA transitively but don’t use it), exclude the auto-configuration:
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
HibernateJpaAutoConfiguration.class
})
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}Or via application.properties:
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfigurationThis is the right fix if you’re using a non-JPA data store (MongoDB, Redis, Elasticsearch) but accidentally pulled in a JPA dependency.
Fix 5: Fix Environment Variable Placeholders
If properties reference environment variables that aren’t set, Spring Boot uses the literal placeholder string as the value:
spring.datasource.url=${DATABASE_URL}If DATABASE_URL isn’t set, Spring Boot gets the string ${DATABASE_URL}, which is not a valid JDBC URL.
Set the environment variables before running:
export DATABASE_URL=jdbc:postgresql://localhost:5432/mydb
export DATABASE_USERNAME=myuser
export DATABASE_PASSWORD=mypassword
java -jar myapp.jarOr provide a default value:
spring.datasource.url=${DATABASE_URL:jdbc:postgresql://localhost:5432/mydb_default}
spring.datasource.username=${DATABASE_USERNAME:dev_user}
spring.datasource.password=${DATABASE_PASSWORD:dev_pass}The syntax ${VAR:default} uses the environment variable if set, or falls back to the default.
Verify the resolved value:
# Enable actuator and check environment
curl http://localhost:8080/actuator/env | jq '.propertySources[] | select(.name | contains("application")) | .properties'Pro Tip: When using
${VAR:default}placeholders, runmvn spring-boot:run -Dspring-boot.run.arguments=--debugand grep the boot output forFailed to bind properties under 'spring.datasource'. The framework prints the literal resolved value, which makes it obvious when an unset variable has fallen through as the string${VAR}. Treat that as a startup precondition check rather than a runtime guess.
Fix 6: Configure H2 for Tests Only
Use a real database in production/dev but H2 for unit/integration tests:
src/main/resources/application.properties:
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.username=myuser
spring.datasource.password=mypasswordsrc/test/resources/application.properties:
# Overrides main properties 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.H2Dialectbuild.gradle / pom.xml:
<!-- H2 as test dependency only -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>Fix 7: Configure Multiple DataSources
If you have multiple databases, you must explicitly configure each DataSource bean — Spring Boot’s auto-configuration only works for a single DataSource. The moment you declare a second DataSource bean, the auto-configured one is suppressed and you have to wire everything explicitly, including the EntityManagerFactory, transaction manager, and JPA repository scan paths.
@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=pass2When configuring multiple DataSources manually, Spring Boot’s auto-configuration backs off. You must configure JPA entities and repositories explicitly for each DataSource. A common mistake is forgetting @EnableJpaRepositories(basePackages = "...", entityManagerFactoryRef = "primaryEntityManagerFactory", transactionManagerRef = "primaryTransactionManager") — without it, every repository in your project tries to use the primary DataSource even when its entities belong to the secondary database, producing cryptic “table does not exist” errors at runtime instead of a clean startup failure.
Common Mistake: Adding
spring.datasource.primary.urlandspring.datasource.secondary.urldoes not magically split the connections. Those properties only do something because of the@ConfigurationProperties("spring.datasource.primary")binding on the bean. Without explicit@Beanmethods, both prefixes are ignored and Spring Boot still looks for the flatspring.datasource.urlkey.
Still Not Working?
Enable Spring Boot debug logging to see exactly what auto-configuration ran and why:
java -jar myapp.jar --debugLook for DataSourceAutoConfiguration in the output — “matched” means it ran, “did not match” shows what condition failed.
Check the full classpath for conflicting drivers:
# Maven
mvn dependency:tree | grep -E "(jdbc|driver|datasource)"
# Gradle
./gradlew dependencies | grep -E "(jdbc|driver|datasource)"Verify the JDBC URL format. A malformed URL causes a “suitable driver class” error even when the driver is present:
# PostgreSQL
jdbc:postgresql://host:port/database
# MySQL
jdbc:mysql://host:port/database
# H2 in-memory
jdbc:h2:mem:dbname
# H2 file-based
jdbc:h2:file:/path/to/dbCheck for the Jakarta vs javax namespace conflict (Boot 3 migration). If you upgraded to Spring Boot 3 and the error still appears with a fresh spring.datasource.url, your project likely still has a transitive dependency referencing javax.persistence.*. Run mvn dependency:tree -Dincludes=javax.persistence:* or ./gradlew dependencyInsight --dependency javax.persistence-api. Any matching results need to be excluded or upgraded — Hibernate 6, Tomcat 10+, and Jakarta-compatible drivers are required.
Check the MySQL connector group ID. On Boot 3.0+, the old mysql:mysql-connector-java artifact still exists but is unmaintained and missing newer driver classes. Switch to com.mysql:mysql-connector-j. If both are on the classpath, Maven picks one based on dependency resolution order, and you may get a driver that does not understand jdbc:mysql:// with the latest URL parameters.
Run with --debug and grep for DataSource. Spring Boot’s autoconfiguration report shows exactly which condition failed. Positive matches confirms what ran; Negative matches lists every condition that prevented DataSourceAutoConfiguration from succeeding. The exact OnPropertyCondition or OnClassCondition line tells you whether the issue is a missing property, missing driver, or both.
For related Spring Boot issues, see Fix: Spring Boot Whitelabel Error Page, Fix: Spring Boot Port Already in Use, Fix: Spring Boot Test Not Working, 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.