DevOps
Enable MySQL Remote Connections on Linux: mysqld.cnf, Port 3306, and Firewall Discipline
MySQL listens on localhost until you say otherwise. When you really need another host on the wire, line up mysqld.cnf bind-address edits, systemd restarts, listener checks, and UFW intent the same way you would for Postgres or Redis on the same VPS.

If you are standing up a MySQL 8 install on Ubuntu before networking hardens anything, treat this note as the follow-on chapter: defaults keep sockets on 127.0.0.1, which is healthy until a second machine honestly needs native drivers instead of SSH tunnels.
⏱️ Estimated time: about five minutes of edits plus whatever your change window demands for reloads.
Why exposing database ports is never “just firewall later”
Opening TCP 3306 toward the public internet is workable in labs and painful in prod. Prefer VPN paths, bastion SSH tunnels, cloud security groups, or IP allow lists; keep passwords and MySQL grants boringly tight; and assume scanners will find the listener if it is globally reachable.
Prerequisites and risk framing
Before opening nano, line up:
- MySQL installed and running with sudo access on the box
- The server IP your clients dial—public, private VPC, or both—written down so grants and firewall rules stay honest
- A MySQL user that may authenticate remotely (
'app'@'%'is easy and lazy; prefer'app'@'10.0.0.12'when you know the sender)
When I rough in UFW sequencing without retyping muscle memory, I still paste from the Nginx + UFW command slab so ufw status verbose cadence matches every other Ubuntu database article on this site.
Parallel bedtime reading: PostgreSQL remote access follows the same story with listen_addresses and pg_hba.conf instead of bind-address—different files, same paranoia.
Edit bind-address in mysqld.cnf
Open the daemon config Ubuntu commonly ships under mysql.conf.d:
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
Find the listener guard:
bind-address = 127.0.0.1
127.0.0.1 means local-only sockets—exactly what you want until remote access is a deliberate policy call.
To let other interfaces accept handshakes, widen it:
bind-address = 0.0.0.0
0.0.0.0 is the blunt instrument: every NIC listens. Prefer pairing it with security groups, VPN paths, or tightly scoped UFW rules rather than treating the change as “job done.”
Restart MySQL and verify port 3306
Reload mysqld so the file matters:
sudo systemctl restart mysql
Watch health:
sudo systemctl status mysql
Confirm something is listening where clients expect:
sudo netstat -tuln | grep 3306
On modern images you can mirror the same signal with ss -tuln | grep 3306 if netstat feels legacy. You want to see 0.0.0.0:3306 (or the explicit IP you bound) instead of only 127.0.0.1:3306.
Firewall: UFW and MySQL port 3306
Host firewalls are the last mile after mysqld listens. A typical wide-open lab rule:
sudo ufw allow 3306/tcp
Production-shaped setups usually pass from constraints or lean on cloud security groups so the entire planet never reaches the port just because UFW said “allow.” If you already trust paste-friendly Ubuntu UFW lines on web-tier boxes, keep that snippet beside this tab—the ordering of allow, enable, and status verbose is the habit, not MySQL-specific grammar.
Troubleshooting remote MySQL connections
When drivers still time out after the edits above, walk the boring checklist:
- Service —
systemctl status mysqlshould be active;journalctl -u mysql -e --no-pagernarrates boot failures faster than guessing. - Listener —
netstat/ssshould prove3306binds beyond localhost once policy requires it. - Privileges —
SELECT user,host FROM mysql.user;should show a row that matches your client origin; anonymous grants are not “convenience,” they are debt. - Edge firewalls — corporate laptops or cloud SGs block outbound SQL more often than people admit.
- Syntax — a stray character in
mysqld.cnfprevents mysqld from applying the bind you think you saved.
For another database with the same “widen bind, restrict path” rhythm, Redis remote access on Ubuntu is a useful cross-check. When you need the ufw allow / reload boilerplate without rereading man pages, that single-page nginx plus UFW snippet is still what I open next to MySQL tabs.
You now know how to flip bind-address, restart mysql, prove 3306 listens, and stack firewall intent so convenience does not steamroll policy—keep the Ubuntu install walkthrough handy when binaries need refresh, and revisit the PostgreSQL listener guide any time two databases share one VPS story.
Frequently asked questions
When is 0.0.0.0 the right bind-address for MySQL?
Reach for 0.0.0.0 when every interface must accept traffic and you already plan to constrain who may route to those interfaces—UFW or cloud rules, VPN-only paths, and MySQL grants scoped to real client networks. When you only need one NIC, binding that address directly often shrinks the accidental blast radius compared with listening everywhere “because it worked in a tutorial.”
Why can clients still not connect after changing bind-address?
Typical culprits are an unsaved config, a skipped systemctl restart mysql, MySQL users that still only allow localhost, another process colliding on 3306, or upstream firewalls (cloud SGs, office egress filters) blocking SQL even though mysqld is perfect locally. Re-read status, ss/netstat, and error logs before assuming the driver string is wrong.
Is opening UFW for port 3306 enough for remote MySQL?
Not by itself. UFW (or any firewall) only shapes packet paths. You still need authentication that matches remote hosts, secrets that survive audits, and—when possible—peers limited to known IPs or tunnels rather than the whole WAN. sudo ufw allow 3306/tcp is a teaching shortcut, not a production seal of approval.
Does MySQL use TCP port 3306 by default for remote clients?
Conventional installs listen on TCP 3306 unless you override port in configuration or front the database with something else entirely. Remote clients therefore aim at hostname:3306 unless your ops team standardized a different listener or jump host path.
Written by Shashikant Dwivedi
Engineer, occasional writer, full-time noticer. Based in Prayagraj, India. New essays land roughly twice a month.
Keep reading
Adjacent essays.
The newsletter
New articles in your inbox.
Occasional articles on engineering, tooling, and software development practices. No marketing, no fluff — just the article, when it's ready.
Unsubscribe with one click. Your email never leaves the list.


