Updated: 18 October 2026 · Applies to: UFW 0.36.2 on Ubuntu 24.04 and firewalld 2.4.3 on AlmaLinux 10.2, tested; the same commands work on Debian, Rocky Linux and RHEL
To open a port for one IP address only, allow that address and that port together, and make sure the port is not also open to everyone. With UFW (Ubuntu, Debian):
sudo ufw allow from 203.0.113.10 to any port 3306 proto tcp
With firewalld (AlmaLinux, Rocky Linux, RHEL), use a rich rule:
sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="203.0.113.10" port port="3306" protocol="tcp" accept' sudo firewall-cmd --reload
Replace 203.0.113.10 with the address that should get in (your office, another server) and 3306 with the port. Below are the variations, how to check and remove the rule, and the mistakes that leave a port open or lock you out.
1. UFW: allow a port from one IP
- Add the rule. The word order matters:
fromthe address,to any portthe port, then the protocol:sudo ufw allow from 203.0.113.10 to any port 3306 proto tcp
UFW answersRule added. (While UFW is still inactive it saysRules updatedinstead.) - Check the result:
sudo ufw status numbered
Lab output on Ubuntu 24.04 after the examples below:To Action From -- ------ ---- [ 1] 3306/tcp ALLOW IN 203.0.113.10 [ 2] 22/tcp ALLOW IN 203.0.113.0/24 [ 3] 80,443/tcp ALLOW IN 203.0.113.10 [ 4] 3306/tcp ALLOW IN 2001:db8::10 - Make sure the port is not open to everyone by an older rule such as
3306/tcp ALLOW IN Anywhere. If it is, delete that rule (section 4).
Variations, all tested with UFW 0.36.2:
- A whole network:
sudo ufw allow from 203.0.113.0/24 to any port 22 proto tcp. - Several ports:
sudo ufw allow proto tcp from 203.0.113.10 to any port 80,443. WithoutprotoUFW refuses:ERROR: Must specify 'tcp' or 'udp' with multiple ports. - An IPv6 address works the same way and answers
Rule added (v6).
Two mistakes to avoid:
sudo ufw allow from 203.0.113.20 port 3306(withoutto any) is accepted, butportthen means the source port of the visitor. The status showsAnywhere ALLOW IN 203.0.113.20 3306: all your ports, for traffic coming from port 3306. Delete such a rule.- UFW checks rules from the top and the first match wins. With
3306/tcp DENY IN Anywhereabove your allow rule, our allowed test client still timed out. Put the allow rule first withsudo ufw insert 1 allow from 203.0.113.10 to any port 3306 proto tcp; after that the client got through.
UFW's default policy drops other traffic silently, so a blocked client waits until it times out instead of getting an error.
2. firewalld: rich rule for one IP and one port
- Add the rule permanently and load it:
sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="203.0.113.10" port port="3306" protocol="tcp" accept' sudo firewall-cmd --reload
Both commands printsuccess. - Check it:
sudo firewall-cmd --zone=public --list-rich-rules
rule family="ipv4" source address="203.0.113.10" port port="3306" protocol="tcp" accept
firewalld turned it into this nftables rule in our lab:ip saddr 203.0.113.10 tcp dport 3306 accept. - Check that the port is not open to everyone as well:
sudo firewall-cmd --zone=public --list-portsand--list-servicesmust not show it. When we added3306/tcpto the zone as a plain port, an address without a rich rule could connect again. Remove such an entry withsudo firewall-cmd --permanent --zone=public --remove-port=3306/tcp(or--remove-service=with the service name shown) and reload.
Variations, all tested on firewalld 2.4.3:
- A whole network:
source address="203.0.113.0/24". - A service instead of a port number:
rule family="ipv4" source address="203.0.113.0/24" service name="ssh" accept. - An IPv6 address needs
family="ipv6":rule family="ipv6" source address="2001:db8::10" port port="3306" protocol="tcp" accept. - Leaving out
familyfails withError: MISSING_FAMILY, and leaving outprotocol="tcp"fails withError: INVALID_PROTOCOL.
In our lab, a client whose address was not in the rule got No route to host (firewalld rejects the packet), and the allowed client got Connection refused because no service was listening yet: the firewall let it through.
3. firewalld: a zone for trusted sources
For several addresses and ports, put the addresses in their own zone instead of writing many rich rules:
sudo firewall-cmd --permanent --new-zone=dbaccess sudo firewall-cmd --reload sudo firewall-cmd --permanent --zone=dbaccess --add-source=203.0.113.10/32 sudo firewall-cmd --permanent --zone=dbaccess --add-port=3306/tcp sudo firewall-cmd --reload sudo firewall-cmd --zone=dbaccess --list-all
Add more addresses or networks with further --add-source lines. firewall-cmd --get-zone-of-source=203.0.113.10/32 then prints dbaccess.
Watch out: traffic from a source in a zone is handled by that zone only. In our test, the client in dbaccess could reach port 3306 but now got No route to host on SSH (port 22), which the public zone still allowed for everyone else. If you put your own admin address into such a zone, add SSH to it first (--zone=dbaccess --add-service=ssh) or you lock yourself out. The built-in trusted zone does the opposite: --zone=trusted --add-source=203.0.113.10 allows everything from that address.
4. Remove the access again
With UFW, repeat the rule after delete, or delete it by its number from ufw status numbered:
sudo ufw delete allow from 203.0.113.10 to any port 3306 proto tcp sudo ufw delete 1
Both printed Rule deleted. A rule for Anywhere also has a (v6) twin: deleting by number removes only one line, deleting by the rule text removes both. With firewalld:
sudo firewall-cmd --permanent --zone=public --remove-rich-rule='rule family="ipv4" source address="203.0.113.10" port port="3306" protocol="tcp" accept' sudo firewall-cmd --permanent --zone=dbaccess --remove-source=203.0.113.10/32 sudo firewall-cmd --permanent --delete-zone=dbaccess sudo firewall-cmd --reload
5. Before you test
- The service must listen on the network address, not only on
127.0.0.1. For MariaDB or MySQL, setbind-addressand allow the database user only from that IP. Check what listens with how to check if a port is in use on Linux. - Test from the allowed machine, for example
nc -zv 198.51.100.5 3306, as in how to check if a remote port is open with nc. - More firewalld commands are in firewall-cmd: list all rules and useful firewalld examples, the basics of opening a port for everyone in how to open a port in Linux, and setting up UFW in how to open ports on Ubuntu with UFW.
Official documentation: firewalld rich language and ufw manual (Ubuntu 24.04).