Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Spring Boot can connect to MySQL and manage tables, but it does not normally create the MySQL server or database for you. The reliable workflow is to start MySQL, create a database and dedicated user, configure Spring Boot’s JDBC connection, then create tables with a migration (recommended) or Hibernate (for a quick local experiment). This guide uses Java 17+, Spring Boot 4.1.0, and MySQL 8.4 as its baseline; use the compatible version offered by Spring Initializr if the available release has changed.

What you need

Choose Maven or Gradle, Java, Jar packaging, and Java 17 or later. Add Spring Data JPA and MySQL Driver. Add Spring Web if you want to test through HTTP, and Flyway Migration if you want versioned schema changes. Spring Boot manages compatible dependency versions, so avoid pinning a Connector/J version without a specific reason. The driver is published as com.mysql:mysql-connector-j; it provides JDBC communication with MySQL, as described in the Connector/J documentation.

A typical Maven project needs these dependencies (keep the Spring Boot parent or dependency management generated by Initializr):

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

For Flyway, add org.flywaydb:flyway-core and org.flywaydb:flyway-mysql, with versions managed by Spring Boot where supported.

Start MySQL and create the database

You can run MySQL outside the application and create the database manually, or use Compose for a repeatable local server. These are alternatives; both leave the same key distinction: the server and database must exist before Spring Boot can use them.

Option 1: Create it in an existing MySQL server

Connect with an administrative account:

mysql -u root -p

Then create a database and a separate application account:

CREATE DATABASE IF NOT EXISTS appdb
  CHARACTER SET utf8mb4
  COLLATE utf8mb4_0900_ai_ci;

CREATE USER IF NOT EXISTS 'appuser'@'localhost'
  IDENTIFIED BY 'change-this-password';

GRANT ALL PRIVILEGES ON appdb.* TO 'appuser'@'localhost';

SHOW DATABASES;
SELECT User, Host FROM mysql.user WHERE User = 'appuser';

CREATE DATABASE is the MySQL operation that creates the database; it is separate from creating tables. See MySQL’s database-creation reference and character-set guidance. The example collation is appropriate for MySQL 8.4; check compatibility before using it with older MySQL-compatible servers.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The broad grant above keeps a local tutorial simple. For a deployed application, use a dedicated account with only the privileges it needs, and configure its permitted host deliberately. MySQL account identity includes both the username and host: 'appuser'@'localhost' is not automatically the same account as 'appuser'@'%'. Do not connect your application as root.

Option 2: Run MySQL with Docker Compose

Create compose.yml in the project directory:

services:
  mysql:
    image: mysql:8.4
    environment:
      MYSQL_DATABASE: appdb
      MYSQL_USER: appuser
      MYSQL_PASSWORD: change-this-password
      MYSQL_ROOT_PASSWORD: change-this-root-password
    ports:
      - "127.0.0.1:3306:3306"
    volumes:
      - mysql-data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 10

volumes:
  mysql-data:

The loopback-only port binding makes this example accessible from the host machine without exposing MySQL on every network interface. Start the service and check its logs:

docker compose up -d
docker compose logs -f mysql

When the application runs on your computer, connect to localhost:3306. When the application itself runs as another Compose service, use mysql:3306 as the host: inside a container, localhost refers to that container, not its MySQL neighbor. A published port is not needed for service-to-service traffic on the Compose network.

A named volume preserves database files when the container is recreated. MySQL’s initialization variables, including the database, user, and passwords, are applied when the data directory is first initialized; changing them later does not rewrite credentials in an existing volume. To reset a disposable local database, you can run docker compose down -v and then docker compose up -d, but -v permanently deletes that volume’s data. A running container is also not proof that MySQL is ready to accept connections; inspect the logs or retry after startup.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Configure Spring Boot’s connection

For an application running on the host with the Compose example above, put this in src/main/resources/application.properties:

spring.datasource.url=jdbc:mysql://localhost:3306/appdb
spring.datasource.username=appuser
spring.datasource.password=${DB_PASSWORD:change-this-password}

spring.jpa.hibernate.ddl-auto=validate
spring.jpa.open-in-view=false

Set the password through the environment in a real project rather than committing a real credential. The fallback shown is only a local tutorial convenience. For example, set DB_PASSWORD in your shell or run configuration. If the application is another Compose service, change the URL to:

spring.datasource.url=jdbc:mysql://mysql:3306/appdb

The URL follows the JDBC form jdbc:mysql://host:port/database. Spring Boot normally infers the MySQL driver from the URL and dependency, so you do not need to set spring.datasource.driver-class-name for this setup. Old tutorials may specify an obsolete driver coordinate or force a dialect property; do not add either without a specific compatibility need.

Create a table and persist a record

With JPA, map a Java class to a table and expose a repository. For example, create src/main/java/com/example/demo/user/User.java:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
package com.example.demo.user;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Column;

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    protected User() {
    }

    public User(String name) {
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}

Use jakarta.persistence imports for current Spring Boot generations; older material may show javax.persistence. @Entity maps the class to a relational entity, @Id marks its primary key, and GenerationType.IDENTITY uses MySQL’s auto-increment style identity. The explicit table name avoids depending on implicit naming conventions.

Then create UserRepository.java in the same package:

package com.example.demo.user;

import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
}

Choose how tables are created

Creating the database and creating its tables are different jobs. Hibernate can create tables from entities, while Flyway or Liquibase can apply explicit, versioned schema changes. Spring Boot also supports SQL initialization scripts, but combining several competing schema-management mechanisms makes startup behavior harder to reason about. Its database initialization guidance recommends using a migration tool on its own when one is present.

Setting or tool Use Trade-off
create Disposable demo or test schema Recreates schema at startup and can destroy data.
create-drop Short-lived tests Creates at startup and drops at shutdown; do not use for data you need to keep.
update Local experimentation Convenient, but not a dependable versioned migration process or production change plan.
validate Schema managed separately Checks entity mappings against tables and fails on mismatch; it does not create a missing table.
none Schema managed outside Hibernate No Hibernate schema action; missing or incorrect schema may surface later.
Flyway or Liquibase Team and production schema changes Provides explicit, ordered changes; requires migration discipline.

For a quick first run, you can temporarily set spring.jpa.hibernate.ddl-auto=update and let Hibernate create the table. Do not treat it as a production migration strategy. For a maintainable project, let Flyway own schema changes and keep Hibernate at validate.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use Flyway for a versioned table

Create src/main/resources/db/migration/V1__create_users_table.sql:

CREATE TABLE users (
    id BIGINT NOT NULL AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    PRIMARY KEY (id)
);

Keep spring.jpa.hibernate.ddl-auto=validate. On startup, Flyway applies the migration to the configured database; Hibernate then checks that the entity mapping agrees with the resulting schema. Flyway’s MySQL reference documents its MySQL support.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Verify the connection and insert a row

For a minimal HTTP check, add a controller. This example accepts and returns an entity directly to keep the setup short; a real API should generally use request/response DTOs, validation, and explicit error handling.

package com.example.demo.user;

import java.util.List;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/users")
public class UserController {
    private final UserRepository repository;

    public UserController(UserRepository repository) {
        this.repository = repository;
    }

    @PostMapping
    public User create(@RequestBody User user) {
        return repository.save(user);
    }

    @GetMapping
    public List<User> findAll() {
        return repository.findAll();
    }
}

Start the application with the Maven wrapper (./mvnw spring-boot:run, or mvn spring-boot:run if you do not have the wrapper), then insert and read a record:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -X POST http://localhost:8080/users 
  -H "Content-Type: application/json" 
  -d '{"name":"Ada"}'

curl http://localhost:8080/users

The POST response should include an assigned ID, and the GET response should include the saved user. You can independently confirm the database state by connecting to MySQL and running:

USE appdb;
SHOW TABLES;
SELECT * FROM users;

If using a Compose-only MySQL service, one local way to connect from the host is docker compose exec mysql mysql -uappuser -p appdb; enter the password when prompted. Avoid placing real passwords in shell history.

Troubleshoot common failures

Error or symptom What to check
Communications link failure or connection refused Confirm MySQL is running and ready, the port is correct, and the URL host matches where the application runs. Use localhost from the host and the Compose service name mysql from a sibling container. Confirm Docker publishes the port if connecting from the host.
Unknown database 'appdb' The server responded, but that database does not exist on that server or the URL names another database. Run SHOW DATABASES; on the same server and create it or correct the URL.
Access denied for user Check the credential and the MySQL account’s host component and grants. A connection through a different hostname or network path may match a different MySQL account. Inspect with SHOW GRANTS FOR 'appuser'@'localhost'; when that is the account in use.
No suitable driver Ensure the MySQL Driver dependency is included, the artifact was rebuilt, and the runtime classpath contains Connector/J. Use the current com.mysql:mysql-connector-j coordinate rather than an old copied coordinate.
Table doesn't exist Check whether schema creation is disabled or set to validate without a migration, whether the migration is under src/main/resources/db/migration, whether it failed in startup logs, and whether SQL and entity table names match.
Compose password changes have no effect An existing named volume retains its initialized database state. Reset only if its contents can be discarded: docker compose down -v deletes the volume, after which Compose initializes a new database.

If you see Public Key Retrieval is not allowed, do not blindly paste an old JDBC parameter as a fix. Check the MySQL authentication configuration, Connector/J version, and TLS requirements for your environment; secure authentication should be configured deliberately.

Before deploying

  • Use a dedicated, least-privilege database account, not MySQL root.
  • Keep secrets out of source control; use deployment environment variables or a secret manager.
  • Use Flyway or Liquibase to version schema changes, and validate mappings rather than silently updating production schema.
  • Use TLS and restrict network access according to the deployment environment.
  • Plan backups, recovery, connection limits/pooling, and health checks; a container health check alone does not guarantee application retries.
  • Keep development, test, staging, and production databases separate. For integration tests that need MySQL-specific behavior, consider Testcontainers rather than assuming an H2 test behaves identically.

Spring Data JPA is not required for every application. If you prefer explicit SQL and do not need ORM mapping, Spring JDBC is a simpler alternative; the Spring MySQL guide discusses both approaches. MySQL-compatible services such as MariaDB can differ in driver behavior, authentication, and SQL features, so verify compatibility rather than assuming they are interchangeable. A managed MySQL service can reduce database-operations work, but is optional; compare backups, availability, networking, operational burden, and workload-specific costs before choosing one.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.