Guides

MySQL port: 3306 and 33060, how to check, change and open it safely

The MySQL port is 3306 by default, plus 33060 for MySQL 8's X Protocol. Check and change it, -P vs -p, safe remote access and connection errors (111, 110).

Published ~8 min read
On this page

Short answer: MySQL and MariaDB listen on TCP port 3306 by default. MySQL 8 also opens 33060 for the X Protocol used by MySQL Shell. Check the real port with SHOW VARIABLES LIKE 'port'; or sudo ss -tlnp | grep 3306, connect to another port with a capital -P, and keep 3306 closed to the internet.

PortProductUsed forReachable from
3306/tcpMySQL, MariaDBThe classic client protocol: applications, the mysql client, mysqladmin, phpMyAdmin, dumpsThe server itself, or one app server
33060/tcpMySQL 5.7.12 and newer, on by default since 8.0X Protocol: MySQL Shell, X DevAPI, Document StoreThe server itself
33062/tcpMySQL 8.0.14 and newerA separate admin connection, only when admin_address is setThe server itself
33061/tcpMySQL Group ReplicationTraffic between group members (the port the manual uses)Other members only
6446, 6447MySQL RouterRead-write and read-only routing in an InnoDB ClusterApp servers only
4567, 4568, 4444MariaDB Galera ClusterReplication, incremental and full state transferOther nodes only
Unix socketBothConnections to localhost: /run/mysqld/mysqld.sock on Debian and Ubuntu, /var/lib/mysql/mysql.sock on RockyLocal processes, no port

MariaDB uses the same port 3306 and has no X Protocol, so on Debian, where the default MySQL packages install MariaDB, you only ever see 3306. Port 3306 is registered with IANA as mysql, which is why ss without -n prints :mysql instead of the number.

How to check which port MySQL is using

Ask the server first. It reports the port it actually opened, whatever the config files say:

sudo mariadb (or sudo mysql)
SHOW VARIABLES WHERE Variable_name IN ('port', 'bind_address', 'skip_networking');
Example output · MariaDB 10.11 on Debian 12
+-----------------+-----------+
| Variable_name   | Value     |
+-----------------+-----------+
| bind_address    | 127.0.0.1 |
| port            | 3306      |
| skip_networking | OFF       |
+-----------------+-----------+
3 rows in set (0.001 sec)
  • port is the TCP port. SELECT @@port; returns the same number on its own.
  • bind_address says on which addresses: 127.0.0.1 means only programs on the server can connect over TCP; 0.0.0.0 or * means every address.
  • skip_networking ON means no TCP at all: the server answers only on its Unix socket, whatever port says.

Then look at the socket table, which also shows the X Protocol port and the process:

Debian · Ubuntu · Rocky
sudo ss -tlnp | grep -E ':3306|:33060'
Example output · MariaDB on Debian 12
LISTEN 0      80        127.0.0.1:3306       0.0.0.0:*    users:(("mariadbd",pid=811,fd=21))
Example output · MySQL 8.0 on Ubuntu
LISTEN 0      151       127.0.0.1:3306       0.0.0.0:*    users:(("mysqld",pid=1042,fd=23))
LISTEN 0      70        127.0.0.1:33060      0.0.0.0:*    users:(("mysqld",pid=1042,fd=21))

127.0.0.1:3306 is the safe default the Debian and Ubuntu packages ship. Rocky Linux sets no bind-address, so there you see *:3306 and only firewalld keeps the port closed. What the other address forms mean is in checking open ports on Linux. To find which file sets the values:

Debian · Ubuntu · Rocky
sudo grep -rnE '^\s*(port|bind-address|bind_address|skip-networking)' /etc/mysql/ /etc/my.cnf /etc/my.cnf.d/ 2>/dev/null

mysqladmin: the port from the command line

Debian · Ubuntu · Rocky
# the port and bind address of the running server
sudo mysqladmin variables | grep -wE 'port|bind_address'

# is a server answering on this host and port?
mysqladmin -h 127.0.0.1 -P 3306 -u app -p ping
Example output
| bind_address        | 127.0.0.1 |
| port                | 3306      |

mysqld is alive

grep -w matches port as a whole word, so extra_port and mysqlx_port stay out of the result. mysqladmin ping with an explicit host and port is a handy health check for scripts: it exits with 0 when the server answers, even if the login itself is refused. On MariaDB the same tool is also called mariadb-admin, and newer MariaDB releases warn that the mysql-prefixed names are deprecated.

-P or -p: the capital letter matters

OptionMeaningExample
-P 3307TCP port (long form --port=3307)mysql -h 127.0.0.1 -P 3307 -u app -p
-pAsk for the password (long form --password)mysql -u app -p
-pSECRETPassword inline, no space. Lands in your shell history, and on some systems in psAvoid; use ~/.my.cnf
-h localhostConnect through the Unix socket, not TCPmysql -h localhost -u app -p
-h 127.0.0.1Connect over TCP to the local servermysql -h 127.0.0.1 -P 3306 -u app -p
--protocol=TCPForce TCP whatever the host namemysql --protocol=TCP -P 3307 -u app -p
-S PATHUse this socket filemysql -S /run/mysqld/mysqld.sock -u app -p

Two mistakes come up again and again:

what goes wrong
$ mysql -u app -p 3307
Enter password:
ERROR 1049 (42000): Unknown database '3307'

Lowercase -p takes the password only when it is glued to the option (-pSECRET), so the separate 3307 is read as the name of a database. The second trap is localhost. The MySQL manual says that on Unix the mysql client treats localhost as “use the socket file”, even when -P names a port, so mysql -h localhost -P 3307 quietly reaches whichever server owns the default socket. MariaDB’s client differs: its man page (10.11, as shipped in Debian 12) says that --port on the command line forces TCP only “without other connection properties”, so a host name next to it can still mean the socket. To be sure with either client, write -h 127.0.0.1 or add --protocol=TCP.

How to change the MySQL port

  1. 1Set the port in the server configuration
    under [mysqld], in the file that holds bind-address
    # MariaDB on Debian/Ubuntu: /etc/mysql/mariadb.conf.d/50-server.cnf
    # MySQL on Ubuntu:          /etc/mysql/mysql.conf.d/mysqld.cnf
    # Rocky:                    a file in /etc/my.cnf.d/
    [mysqld]
    port = 3307
  2. 2Rocky and AlmaLinux: tell SELinux about the new port
    Rocky · AlmaLinux
    sudo semanage port -a -t mysqld_port_t -p tcp 3307

    Without it, SELinux stops the server from binding the port and it fails to start. semanage comes with policycoreutils-python-utils.

  3. 3Restart and check
    Debian · Ubuntu · Rocky
    sudo systemctl restart mariadb     # or: mysql (Ubuntu), mysqld (Rocky)
    sudo ss -tlnp | grep 3307
  4. 4Update every client that connects over TCP
    ~/.my.cnf (mode 600)
    [client]
    port = 3307

    Applications that connect to 127.0.0.1 need the new port in their settings, for example define( 'DB_HOST', '127.0.0.1:3307' ); in WordPress’s wp-config.php. Anything that uses localhost through the socket (PHP’s default for localhost, sudo mariadb) keeps working unchanged, because a socket has no port.

If the port is open to a remote app server, move the firewall rule to the new number too. Changing the port is housekeeping, not security: scanners try every port, and what protects a database is the bind address and the firewall, as with changing the SSH port.

Remote access to port 3306, done safely

Who connectsPort 3306 open?How
An app on the same serverNolocalhost (socket) or 127.0.0.1
You, with a GUI tool or the mysql clientNoAn SSH tunnel to 127.0.0.1:3306
An app server in a private network or VPNOnly on that interfacebind-address set to the private or WireGuard address
An app server across the internetOnly for that one IPbind-address 0.0.0.0, a firewall rule for the IP, a user for that host, TLS

The tunnel is the right answer far more often than people expect. It needs nothing on the server beyond SSH:

on your computer
ssh -N -L 3307:127.0.0.1:3306 you@203.0.113.10
# then, in a second terminal or in your GUI tool:
mysql -h 127.0.0.1 -P 3307 -u app -p

Local port 3307 avoids a clash with a database on your own computer. SSH tunnels covers keeping one open, and the built-in tunnel option of DBeaver, HeidiSQL and MySQL Workbench does the same thing. When an app server elsewhere truly needs a direct connection, open the port to its address only:

on the database server
# firewall: one source address, TCP 3306
sudo ufw allow from 198.51.100.7 to any port 3306 proto tcp

# in sudo mariadb / sudo mysql: a user for that host only, TLS required
CREATE USER 'app'@'198.51.100.7' IDENTIFIED BY 'a-long-random-password' REQUIRE SSL;
GRANT ALL PRIVILEGES ON app.* TO 'app'@'198.51.100.7';

REQUIRE SSL works once the server has a certificate: MySQL 8 creates one by itself, MariaDB 10.11 needs ssl_cert and ssl_key set. The full walkthrough, including bind-address and firewalld, is in installing MariaDB or MySQL.

Port 33060: the X Protocol

MySQL’s X Plugin speaks a second protocol on 33060, used by MySQL Shell, the X DevAPI connectors and the Document Store (JSON collections). Ordinary applications, PHP, WordPress and phpMyAdmin use 3306 only.

sudo mysql
SHOW VARIABLES LIKE 'mysqlx%port';
SHOW VARIABLES LIKE 'mysqlx_bind_address';

Ubuntu’s mysqld.cnf binds it to 127.0.0.1 with mysqlx-bind-address, next to bind-address. If nothing uses it, switch the plugin off with mysqlx = OFF under [mysqld] and restart. MySQL Shell then connects over the classic protocol with mysqlsh mysql://app@127.0.0.1:3306.

Connection errors and what the numbers mean

The number in brackets at the end of a Can't connect error is the operating system’s error code, and it tells you which side to fix. MariaDB’s client words it as Can't connect to server on '203.0.113.10' (111), with the same numbers.

ErrorMeaningFix
ERROR 2003 (HY000): Can't connect to MySQL server on '203.0.113.10:3306' (111)Connection refused: the host answered, but nothing listens on that address and portbind-address still 127.0.0.1, skip_networking on, wrong port, or the server is down
... (110)Timed out: packets are dropped on the way (MariaDB's client may show 115 here instead)A firewall (on the server or the provider's), or the wrong IP
... (113)No route to hostUsually firewalld rejecting the port; add the rich rule
... (10061) or (10060)The Windows codes for refused and timed outAs for 111 and 110; on a Windows server also check that the MySQL service runs
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)localhost means the socket, and there is no socket: the server is not running, or uses another pathsystemctl status mariadb (or mysql); or connect with -h 127.0.0.1
ERROR 1130 (HY000): Host '198.51.100.7' is not allowed to connect to this MySQL serverThe port is fine; no account exists for that client addressCREATE USER for that host (MariaDB says MariaDB server)
ERROR 1045 (28000): Access denied for userThe port is fine; the user, password or authentication plugin is notSee the access denied guide below
ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet'TCP connected, but no MySQL greeting came backSomething else answers on that port, or a tunnel points to a closed port

For Access denied for user 'root'@'localhost' in particular, the cause is almost never the port; read MySQL access denied for root. To test the port alone from the app server, without credentials:

from the app server
nc -vz -w 5 203.0.113.10 3306                        # Linux, macOS
Test-NetConnection 203.0.113.10 -Port 3306           # Windows PowerShell

Where the database should run

On a single VPS that runs both the app and the database, the database never needs a public port: keep bind-address = 127.0.0.1, let the app use localhost, and do admin work through the tunnel. Once you split them across two servers, keep both in the same location: VMHeaven runs VPS in Amsterdam and Frankfurt, and an app in one city querying a database in the other pays that round trip on every query.

Frequently asked

What is the default MySQL port?

TCP port 3306, for both MySQL and MariaDB. MySQL 8.0 and newer also listen on 33060 for the X Protocol used by MySQL Shell (MySQL 5.7.12 to 5.7 offered it only as a plugin you installed). Connections to localhost usually go through the Unix socket and use no port at all.

How do I find which port MySQL is running on?

Run SHOW VARIABLES LIKE 'port'; in the mysql or mariadb client, or sudo mysqladmin variables | grep -w port in the shell. sudo ss -tlnp | grep 3306 shows whether the server listens on that port, on which address and under which process.

How do I connect to MySQL on a different port?

Use a capital -P together with a TCP host: mysql -h 127.0.0.1 -P 3307 -u app -p. Lowercase -p asks for the password. With -h localhost, Oracle's mysql client uses the Unix socket and ignores -P, so write 127.0.0.1 or add --protocol=TCP.

Is it safe to open port 3306 to the internet?

No. Keep MySQL on 127.0.0.1 and connect remotely through an SSH tunnel. If an application server elsewhere must connect directly, allow port 3306 in the firewall only from that server's IP address, create the database user for that host only, and require TLS.

Related articles

All guides