eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – Spring Sale 2026 – NPI EA (cat= Baeldung)
announcement - icon

Yes, we're now running our Spring Sale. All Courses are 30% off until 31st March, 2026

>> EXPLORE ACCESS NOW

Partner – Diagrid – NPI EA (cat= Testing)
announcement - icon

In distributed systems, managing multi-step processes (e.g., validating a driver, calculating fares, notifying users) can be difficult. We need to manage state, scattered retry logic, and maintain context when services fail.

Dapr Workflows solves this via Durable Execution which includes automatic state persistence, replaying workflows after failures and built-in resilience through retries, timeouts and error handling.

In this tutorial, we'll see how to orchestrate a multi-step flow for a ride-hailing application by integrating Dapr Workflows and Spring Boot:

>> Dapr Workflows With PubSub

Course – Spring Sale 2026 – NPI (cat=Baeldung)
announcement - icon

Yes, we're now running our Spring Sale. All Courses are 30% off until 31st March, 2026

>> EXPLORE ACCESS NOW

1. Overview

Secure Shell (SSH) allows us to securely access and manage remote systems, including executing commands, transferring files, and tunneling services.

We can establish a connection to a remote MySQL database through an SSH session. Several SSH clients exist in Java, and one of the most common is Java Secure Channel (JSch).

In this tutorial, we’ll explore how to connect to a MySQL database running on localhost of a remote server through an SSH session.

2. Understanding SSH Port Forwarding

Port forwarding allows the transfer of data between a client system and a remote server by directing traffic from a local port to a port on the remote server over an SSH connection.

This is especially useful when firewalls or other restrictions block direct connection to a remote server’s IP and port.

In our case, the MySQL server is running on localhost of the remote machine, typically using port 3306. While it’s technically possible to connect directly to the remote server’s IP and MySQL port, this is often restricted for security purposes. Instead, we can use local port forwarding over SSH to establish a secure connection to the database.

In local port forwarding, we allocate an available port on our local machine and bind it with the port of the MySQL server running remotely to allow data communication between our program and the remote server.

3. Maven Dependencies

To begin, let’s add the JSch and MySQL connector dependencies to the pom.xml:

<dependency>
    <groupId>com.github.mwiede</groupId>
    <artifactId>jsch</artifactId>
    <version>0.2.20</version>
</dependency>

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>9.0.0</version>
</dependency>

The JSch dependency provides classes like Session, which are essential for establishing an SSH connection to a remote server. Also, the MySQL connector allows us to establish a connection to a running MySQL server.

4. Connection Details

Furthermore, let’s define the connection details to the remote server:

private static final String HOST = "HOST";
private static final String USER = "USERNAME";
private static final String PRIVATE_KEY = "PATH_TO_PRIVATEKEY";
private static final int PORT = 22;

In the code above, we define the necessary credentials to create an SSH session. Next, let’s define the connection details to the remote database:

private static final String DATABASE_HOST = "localhost";
private static final int DATABASE_PORT = 3306;
private static final String DATABASE_USERNAME = "DATABASE_USERNAME";
private static final String DATABASE_PASSWORD = "DATABASE_PASSWORD";

The MySQL database is running on a remote machine’s localhost, using port 3306. We define the database username and password to authenticate the connection.

5. Creating SSH Session

After defining our connection details, let’s create a JSch instance to bootstrap a connection to the remote server:

JSch jsch = new JSch();
jsch.addIdentity(PRIVATE_KEY);

Here, we use a private key to authenticate our identity. However, we can also use password-based authentication.

Next, let’s create a new SSH session:

Session session = jsch.getSession(USER, HOST, PORT);
session.setConfig("StrictHostKeyChecking", "no");
session.connect();

In the code above, we create a new Session with our connection details and disable key host checking for simplicity. Disabling host key checking is convenient for testing but should be avoided in production for security purposes.

Finally, we invoke the connect() method on the Session object to open a new SSH session.

6. Connecting to MySQL Through Port Forwarding

Next, let’s use SSH port forwarding to tunnel the MySQL port:

int port = session.setPortForwardingL(0, DATABASE_HOST, DATABASE_PORT);

In the code above, we invoke the setPortForwardingL() method on the Session object to set up a local port forwarding. By passing 0 as the local port, the program dynamically chooses an available local port for forwarding traffic to the remote MySQL server’s port 3306.

Port forwarding (tunneling) allows traffic sent to a local port to be forwarded through the SSH connection to the MySQL server on the remote machine.

Moreover, let’s use the forward port to connect to the MySQL server:

String databaseUrl = "jdbc:mysql://" + DATABASE_HOST + ":" + port + "/baeldung";
Connection connection = DriverManager.getConnection(databaseUrl, DATABASE_USERNAME, DATABASE_PASSWORD);

In the code above, we establish a connection to the database using the JDBC Connection class. In our database URL, we use the forwarded local port instead of the remote MySQL server’s default port (3306).

Furthermore, let’s verify that the connection exists:

assertNotNull(connection);

In the code above, we assert that the connection to the database is not null.

7. Simple Queries

Additionally, let’s perform some database operations on the established connection. First, let’s create a table:

String createTableSQL = "CREATE TABLE test_table (id INT, data VARCHAR(255))";
try (Statement statement = connection.createStatement()) {
    statement.execute(createTableSQL);
}

Here, we create a test_table in the baeldung database. Next, let’s insert a single record into the created table:

String insertDataSQL = "INSERT INTO test_table (id, data) VALUES (1, 'test data')";
try (Statement statement = connection.createStatement()) {
    statement.execute(insertDataSQL);
}

Finally, let’s assert that the created table is present in the database:

try (Statement statement = connection.createStatement()) {
    ResultSet resultSet = statement.executeQuery("SHOW TABLES LIKE 'test_table'");
    return resultSet.next();
} 

In the code above, we verify that the created table exists in the database.

8. Closing Connection

Essentially, we need to close the SSH session and database connection after the operation:

session.disconnect();
connection.close();

In the code above we invoke the disconnect() and close() methods on the Session and Connection objects respectively to free up resources. It also prevents potential memory leaks.

9. Conclusion

In this article, we learned how to connect to a remote database via an SSH session. Additionally, we learned local port forwarding and applied it to connect to a remote MySQL database through an established SSH session.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

Course – Spring Sale 2026 – NPI EA (cat= Baeldung)
announcement - icon

Yes, we're now running our Spring Sale. All Courses are 30% off until 31st March, 2026

>> EXPLORE ACCESS NOW

Course – Spring Sale 2026 – NPI (All)
announcement - icon

Yes, we're now running our Spring Sale. All Courses are 30% off until 31st March, 2026

>> EXPLORE ACCESS NOW

eBook Jackson – NPI EA – 3 (cat = Jackson)