What port 3306 is
TCP port 3306 is the default port of the MySQL and MariaDB servers. Clients such as the mysql command line tool, PHP, WordPress and most ORMs connect there with the MySQL protocol. MySQL 8 also opens 33060 for the X Protocol used by MySQL Shell and the document store.
Traffic on 3306 is unencrypted unless TLS is set up. MySQL 5.7 and later generate a self-signed certificate automatically and modern clients try TLS first, but whether it is required depends on your server and client settings.
Should it be open to the internet?
Almost never. A public 3306 attracts constant password guessing. Most sites run the database on the same host as the application or on a private network, so it only needs to listen on loopback or a private address. For remote administration, use an SSH tunnel:
ssh -L 3306:127.0.0.1:3306 user@db.example.com
mysql -h 127.0.0.1 -P 3306 -u admin -p
bind-address
Which interfaces MySQL listens on is set by bind-address in my.cnf (on Debian and Ubuntu, /etc/mysql/mysql.conf.d/mysqld.cnf or /etc/mysql/mariadb.conf.d/50-server.cnf):
[mysqld]
bind-address = 127.0.0.1
Debian and Ubuntu packages ship with 127.0.0.1; other builds may listen on all interfaces. To allow a second server on a private network, bind to the private address, then create a user limited to that host:
CREATE USER 'app'@'192.0.2.20' IDENTIFIED BY 'a-long-random-password';
GRANT SELECT, INSERT, UPDATE, DELETE ON shop.* TO 'app'@'192.0.2.20';
Avoid 'user'@'%', which allows logins from any address.
Firewall rules
With ufw, allow one application server only:
sudo ufw allow from 192.0.2.20 to any port 3306 proto tcp
With iptables:
sudo iptables -A INPUT -p tcp -s 192.0.2.20 --dport 3306 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 3306 -j DROP
With Docker, publish the port on loopback (-p 127.0.0.1:3306:3306) or not at all; ports published on all interfaces bypass ufw on most Linux hosts.
How to check what is listening
sudo ss -tlnp | grep ':3306'
sudo lsof -i :3306
mysql -e "SHOW VARIABLES LIKE 'port'; SHOW VARIABLES LIKE 'bind_address';"
A line with 127.0.0.1:3306 means local only; 0.0.0.0:3306 or *:3306 means every interface.
"Port 3306 already in use"
Usually a second MySQL or MariaDB is running: a system service plus a Docker container, or XAMPP alongside a native install. Find it with sudo lsof -i :3306 (on Windows, netstat -ano | findstr :3306), then stop one of them, or move the new one to another port with port = 3307 in its config or -p 3307:3306 in Docker.
Security notes
- Run
mysql_secure_installationon new servers to remove anonymous users and the test database. - Require TLS for remote users with
ALTER USER ... REQUIRE SSL. - Give applications only the privileges they use, never
ALLon*.*. - Keep the server patched and watch the error log for failed logins.
Related ports
- Port 5432: PostgreSQL.
- Port 1433: Microsoft SQL Server.
- Port 6379: Redis, often next to MySQL as a cache.
- Port 22: SSH, for tunnels.
Check whether 3306 is reachable from the public internet with the Port Scanner.