Skip to content

Fix: Spring Boot Failed to Configure DataSource (DataSource Auto-Configuration Error)

FixDevs · (Updated: )

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.

The Error

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 class

Or 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 jdbcUrl

Or 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 class

Why This Happens

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.url is 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.xml or build.gradle, or scoped as provided when it should be runtime.
  • Wrong JDBC URL format — the URL does not match the driver’s expected format. PostgreSQL wants jdbc:postgresql://, MySQL wants jdbc:mysql://, Oracle wants jdbc: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-jpa triggers DataSource auto-configuration. If you do not need a database, exclude it.
  • Profile-specific properties not loadedapplication-prod.yml was not packaged into the jar, or SPRING_PROFILES_ACTIVE was not set in the deployment environment.

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=true

YAML 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.PostgreSQLDialect

Note: driver-class-name is optional when the JDBC URL prefix matches a known driver on the classpath. Spring Boot infers the driver from jdbc: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 postgresql

Fix 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.SocketFactory

MySQL:

# 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 configurations

SQL Server:

spring.datasource.url=jdbc:sqlserver://localhost:1433;databaseName=mydb;encrypt=false
spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver

H2 (file-based instead of in-memory):

spring.datasource.url=jdbc:h2:file:./data/mydb;AUTO_SERVER=TRUE

Fix 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.jar

Spring Boot also reads from .env via system properties at runtime:

java -DDATABASE_URL=jdbc:postgresql://localhost:5432/mydb -jar app.jar

For 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.jar

Fix 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.HibernateJpaAutoConfiguration

Fix 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 myschema

Diagnose pool exhaustion:

# Enable HikariCP logging
logging.level.com.zaxxer.hikari=DEBUG
logging.level.com.zaxxer.hikari.HikariConfig=DEBUG

Fix 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 5432

Simple 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());
        }
    }
}

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/health returning DOWN with component db (Hikari reports pool status here)
  • Kubernetes startupProbe failures incrementing on the new pod
  • Container restart count climbing without ever reaching Ready
  • Log pattern APPLICATION FAILED TO START matched in your log aggregator
  • Metrics: hikaricp_connections_active flat at zero after pod start

Recovery playbook:

  1. Stop the rolloutkubectl rollout pause deployment/<name> or pause the pipeline. Do not let more pods cycle through the failure.
  2. Roll back to last known goodkubectl rollout undo deployment/<name> restores the previous ReplicaSet. This buys you time.
  3. 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, or SPRING_DATASOURCE_PASSWORD.
  4. Verify the secret was actually injectedkubectl exec into 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.
  5. Test connectivity from the pod networknc -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 readinessProbe hit /actuator/health/readiness so pods do not receive traffic until the DataSource is actually live.
  • Gate deploys on a smoke test that hits a /healthz endpoint 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.

Still Not Working?

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 -p

Check 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.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles