DEV Community

dpm_bush
dpm_bush

Posted on Originally published at sshflow.com

MySQL Port 3306: Check the Listener, Test Access, and Connect Safely

A successful connection to TCP port 3306 tells you that something accepted a network connection. It does not prove that the service is MySQL, or that your database username and password will work.

Port 3306 is the default TCP port for MySQL’s classic client-server protocol, and MariaDB commonly uses it too. Here’s how to check each layer when a database connection fails—and how to reach a remote database without exposing it broadly.

Start with the right port and protocol

A typical MySQL client connects to a host on TCP port 3306:

mysql --protocol=TCP -h db.example.net -P 3306 -u app_user -p
Enter fullscreen mode Exit fullscreen mode

The capital -P selects the TCP port. The lowercase -p prompts for a password. Adding --protocol=TCP makes the transport explicit, which is useful when diagnosing connections that might otherwise use a local socket.

Port 3306 is not a guarantee about what’s running there. MySQL can be configured to use a different port, and another process can occupy 3306. MySQL’s X Protocol commonly uses TCP port 33060 when enabled; it’s a separate protocol, not a port every installation necessarily listens on.

Check the server before changing firewall rules

On the database server, inspect whether a process is listening on port 3306:

sudo ss -ltnp 'sport = :3306'
Enter fullscreen mode Exit fullscreen mode

If ss doesn’t show process details, and lsof is installed, try:

sudo lsof -nP -iTCP:3306 -sTCP:LISTEN
Enter fullscreen mode Exit fullscreen mode

Pay attention to the local address. A listener on 127.0.0.1:3306 accepts connections only through the server’s IPv4 loopback interface. A listener on 0.0.0.0:3306 is bound to all IPv4 interfaces, but that alone does not mean it’s reachable from the internet: firewalls and network rules still apply. IPv6 listeners may appear separately.

If you’re unfamiliar with interpreting listening sockets, this Linux guide to checking open ports explains what the output can—and can’t—tell you.

On Windows, check local listening connections in PowerShell with:

Get-NetTCPConnection -State Listen -LocalPort 3306
Enter fullscreen mode Exit fullscreen mode

A missing listener is a server-side problem to investigate: confirm the database is running, check its configured port, and inspect its bind address. Opening a firewall rule won’t start MySQL or make a loopback-only listener reachable remotely.

Test network access separately from login

From a Windows client, test whether the host accepts a TCP connection on 3306:

Test-NetConnection db.example.net -Port 3306
Enter fullscreen mode Exit fullscreen mode

On Linux or macOS, if Netcat is available:

nc -vz db.example.net 3306
Enter fullscreen mode Exit fullscreen mode

These checks test the network path, not database authentication. For an end-to-end login test, use the MySQL client:

mysql --protocol=TCP -h db.example.net -P 3306 -u app_user -p
Enter fullscreen mode Exit fullscreen mode

On Unix-like systems, a MySQL client connecting to localhost may use a Unix socket instead of TCP. If you specifically need to test local TCP, use 127.0.0.1 and --protocol=TCP:

mysql --protocol=TCP -h 127.0.0.1 -P 3306 -u app_user -p
Enter fullscreen mode Exit fullscreen mode

That distinction helps avoid treating a socket connection as proof that a TCP listener is available.

Read the failure as a clue

The error usually tells you which layer to inspect next:

  • Connection refused: Nothing may be listening at that address and port, or the host rejected the connection. Check the service, port, and bind address.
  • Connection timed out: The request may be blocked, routed incorrectly, or sent to the wrong host. Check the destination and network or cloud firewall rules.
  • Access denied: The connection reached MySQL, but authentication or authorization failed. Check the account, password, host-based grants, and database permissions.
  • Address already in use: A process already owns that local port, or another database instance is trying to bind to it. Identify the listener before stopping anything; it may be the instance you need.

A listening socket, a reachable TCP port, and a successful database login are three different checks. Testing them separately makes troubleshooting much faster.

Reach a remote database without exposing 3306

If you can SSH to the database server, you can forward a local port through that SSH connection. This example maps local port 3307 to port 3306 on the SSH server:

ssh -L 3307:127.0.0.1:3306 user@db.example.net
Enter fullscreen mode Exit fullscreen mode

Keep that session open. In another terminal, connect your database client to the local end:

mysql --protocol=TCP -h 127.0.0.1 -P 3307 -u app_user -p
Enter fullscreen mode Exit fullscreen mode

The client connects to local port 3307; SSH carries the traffic to 127.0.0.1:3306 as seen from the SSH server. The database still requires valid credentials and permissions. This approach can avoid making MySQL’s port directly reachable from the public internet. For more on how local forwarding works, see this guide to SSH tunnels and port forwarding.

For remote access, prefer a private network or a narrowly restricted source address over broad public exposure. Changing MySQL’s port alone is not an access control. If you do change it, update the server configuration and clients separately: the client’s -P option chooses where it connects; it does not change the server’s listening port.

I originally published a more detailed version of this guide on the SSHFlow blog.

I'm also building SSHFlow — an SSH client where every server gets its own workspace for terminals, SFTP, code, and databases.

Top comments (0)