The MySQL port
The MySQL port is the TCP number a MySQL server binds to when it accepts client connections, and on a stock installation that port is 3306.

Whether you are opening a firewall, chasing a "connection refused" error, or moving a database to a quieter port, everything starts from that single default number, so the rest of this page works from 3306 outward: how to change it, how to open it in the firewall, and how to diagnose it when it is not there.
The rest of the page moves through the everyday work of MySQL in practice, and it leans on a MySQL Workbench walkthrough for the GUI side of things, a Choosing between MySQL and PostgreSQL comparison for the moment you pick an engine, and a Kill a Process on Linux exercise for the rare case where the server will not stop on its own.
What the default port 3306 actually means
The number 3306 is the default TCP port that MySQL and MariaDB bind to at startup. The server writes it into a socket address, and every client, from the mysql CLI to an application driver, points at that same 3306 unless you tell it otherwise. The port is a network number, not a file path, and it lives next to a handful of well-known service ports such as 22 for SSH, 80 for HTTP and 8080 for a common alternate web server, so when a packet is dropped it is usually the firewall, not MySQL, that is to blame. The server reports the value it is using at the very top of the error log, and it is a one-line grep that saves a long afternoon.
Where the port is set in the config file
The port is set in the server config file, and on most Linux distributions that file is /etc/my.cnf or the /etc/mysql/conf.d/ directory that feeds it. You add or edit one key, port, and the value you choose replaces 3306. The same file also carries the bind_address, which controls which interface the port listens on, and the two settings work as a pair: a port on 0.0.0.0 is reachable from any network, while a port on 127.0.0.1 is local-only. Below is the minimal block that changes the port to 3307 and keeps the server on the local interface.
| Setting | Default | Changed value | Effect |
|---|---|---|---|
| port | 3306 | 3307 | TCP port the server listens on |
| bind_address | 0.0.0.0 | 127.0.0.1 | Restricts the port to the loopback interface |
After you save the file you restart the service, and the change is live the moment the process comes back. The restart is the step people skip and then wonder why 3306 is still open, and on a systemd host the command is a single systemctl restart mysql. If you want the server on a non-default port for a test database, 3307 and 3308 are the two numbers that keep things tidy and avoid colliding with anything else on the box.
Opening the port in the firewall
The firewall must allow the port, and if the rule is missing the connection fails at the network layer before MySQL ever sees it. On a UFW host the rule is one command per port, and you allow the new port the same way you allowed the original 3306. The order matters only in the sense that the service must be running before the test is meaningful, but the rule itself does not care about that. Below is the sequence that opens 3307 for a specific client and confirms the filter is not the problem.
- Allow the port: ufw allow 3307/tcp
- Reload the filter: ufw reload
- Verify the rule: ufw status | grep 3307
- Test from the client: nc -vz dbhost 3307
If the last step returns "succeeded" the path is open and MySQL is reachable, and any failure after that is an application problem. The firewall and the port are two separate checks, and separating them is the fastest way to tell whether a refusal comes from the network or from the server. You apply the same two-step split to SSH on 22 and to the web server on 80, which is why the habit transfers to the rest of the stack.
Diagnosing a connection-refused error
A connection-refused error means the port is not listening, and the diagnosis starts by finding out whether the process is up and which address it bound. The first command checks the port itself, and it tells you in one line whether anything is bound to 3306. The second command reads the server config to confirm the port value the server thinks it is using. A mismatch between the two is the most common root cause, and it happens when the config was edited but the service was not restarted. The two checks, in order, are:
- ss -ltn | grep 3306 to see if the port is bound
- grep port /etc/my.cnf to confirm the configured value
If nothing is bound to 3306 and the config still says 3306, the service is down, and you read the journal with journalctl -u mysql to find the startup error. If the config says 3307 but you are testing 3306, you are simply on the wrong port, and you retest against 3307. The error message, the ss output and the config value form a 3-item chain, and when all three agree the problem is elsewhere, usually the client host name or a second firewall on the client side. A refused connection is different from a timeout, and a timeout means the packet never reached the port, which is a firewall or a routing issue rather than a service issue.
When you change the port, what else follows
Changing the port follows every client that was pointed at the old number, and the change is complete only when the last client has been updated. The three places that usually hold the old 3306 are the application connection string, any firewall allow rules you added for it, and any monitoring or backup scripts that dial the port directly. A typical application keeps the port in one line of its config, and on a PHP stack that line lives in a .env file or a config class that the framework loads on boot. Below is the mapping of where the old port hides and what you update for each.
| Location | What to update | Typical file |
|---|---|---|
| Application string | Replace 3306 with 3307 | .env or config.php |
| Firewall rules | Add the new port, drop the old | ufw rule set |
| Monitoring scripts | New port in the dial list | backup.sh, status script |
The port is only one knob in the server configuration, and it sits next to the timeout, the buffer sizes and the log settings that a full configuration file carries. On a production host you change one value at a time and restart between changes, because a second change that breaks the service on top of the first one doubles the time to find the fault. The 30 second restart is the cost you pay for that discipline, and it is cheap compared with a long outage. When the port work is done you are back at the same diagnosis loop from the previous section, only testing the new number, which is the point at which the change is verified end to end.