MikroTik port forwarding not working comes down to one of six things, and the fastest way through them is to check in the order RouterOS processes the packet. The Packet Flow in RouterOS diagram puts dst-nat in prerouting, before the routing decision and before the filter forward chain. So the dst-nat rule sees the packet first, the forward chain sees it already rewritten to the private address, and the reply has to come back through the same router. Each check below maps to one stage.
For a new installation, first use the MikroTik router setup checklist to verify WAN connectivity, client access and management restrictions.
What a working forward looks like on a default config
On a router that still carries the default firewall, a port forward is one rule:
/ip firewall nat
add chain=dstnat action=dst-nat protocol=tcp dst-port=443 in-interface-list=WAN \
to-addresses=192.168.88.10 to-ports=443 comment="fwd https to web01"
That is the shape of the example in MikroTik’s NAT documentation, which forwards TCP 22 on 172.16.16.1 to 10.0.0.3. Nothing else is needed on a defconf box because of one filter rule that Building Advanced Firewall lists verbatim:
add action=drop chain=forward comment="defconf: drop all from WAN not DSTNATed" \
connection-nat-state=!dstnat connection-state=new in-interface-list=WAN
Read the negation. New connections from WAN are dropped unless a dst-nat rule already claimed them, so a forward needs no separate accept. If you replaced the default firewall with your own and it ends in a plain chain=forward action=drop, add the mirror image above the drop and below the established,related accept:
add chain=forward action=accept connection-nat-state=dstnat connection-state=new in-interface-list=WAN
Order matters; the firewall rules explainer covers why. Browse the firewall and NAT guides for related filtering and VPN configuration.
Check 1: does the dst-nat counter move?
From a phone on LTE, hit the port. Then on the router:
/ip firewall nat print stats
If the packet counter on the dst-nat rule stays at zero, the packet never matched. Most common first:
- Wrong ingress interface. On a PPPoE WAN the public address lives on
pppoe-out1;ether1only carries PPPoE frames, soin-interface=ether1never matches. Usein-interface-list=WANand confirm membership with/interface list member print, as in the PPPoE client guide. - Hard-coded
dst-address=on a dynamic WAN. The address changed, the rule died.dst-address-type=localmatches any address assigned to a router interface, per the matchers reference, and survives the change. - Wrong protocol. WireGuard, most game servers and DNS are UDP. A
protocol=tcpforward for a UDP service matches nothing. - A broader dst-nat rule above yours. NAT evaluates only the first packet of a connection and connection tracking applies the result to the rest, so the first matching rule wins.
Counter at zero with a correct-looking rule? Sniff the WAN before blaming the config: /tool sniffer quick interface=pppoe-out1 port=443. No SYN arriving means the problem is upstream (Check 5).
Check 2: the forward chain and rule shadowing
Counter moves, still no service? Now the forward chain:
/ip firewall filter print stats chain=forward
Watch the defconf drop rule during the test. Two edits break it. Someone removes connection-nat-state=!dstnat “to tighten things up”, which turns it into drop-everything-from-WAN. Or a custom accept for the port sits below a drop-all and is shadowed, with zero hits forever.
One trap for diagnostics rather than traffic: the default fasttrack-connection rule. The packet-flow page states that FastTrack packets bypass the firewall and connection tracking, so once a forwarded connection is established your filter counters stop moving even though it works. Judge the forward by the dst-nat counter and the connection table, not by later filter hits.
Check 3: you are testing from inside (hairpin NAT)
The most common false alarm. A LAN client at 192.168.88.50 opens a connection to the public IP. dst-nat rewrites the destination to 192.168.88.10; the source is untouched. web01 replies directly to .50 across the switch, the reply carries .10 as its source, the client expected the public IP, and the connection is dropped. The forward “works from outside, not from inside”.
RFC 4787 REQ-9 says a NAT MUST support hairpinning. RouterOS does, but only when you add the srcnat rule that forces replies back through the router. MikroTik’s NAT page gives the pattern; with the addresses above:
/ip firewall nat
add chain=srcnat action=masquerade src-address=192.168.88.0/24 dst-address=192.168.88.10 \
protocol=tcp dst-port=443 comment="hairpin https"
The dst-nat rule must also match LAN-originated packets, which arrive on the bridge, not on in-interface-list=WAN. A June 2025 forum thread on a hAP ax2 running RouterOS 7.17 ended with exactly that fix: replace the interface-list match with dst-address-type=local, add the masquerade, and let the forward chain accept dst-natted traffic from LAN too. Trade-off: web01’s logs now show every hairpinned client as the router’s LAN address. Split DNS, returning 192.168.88.10 for the hostname inside, avoids that and is the cleaner design.
Check 4: the host behind the forward
A January 2024 thread on an RB750Gr3 with new VLANs is the canonical case. Sniffing showed packets reaching 192.168.10.150 on the right port and nothing coming back. The router was fine; every target device had the wrong default gateway. A host that cannot route back to the client’s public address cannot answer a forward.
Inspect the tracked connections during a test:
/ip firewall connection print detail where protocol=tcp
The connection tracking reference distinguishes the original dst-address from reply-src-address. For this forward, the original destination is the WAN address the client contacted; the reply source is the translated host, 192.168.88.10. Do not search the original destination field for that private host.
Use the field format shown by your RouterOS version. When addresses and ports are separate fields, narrow the output with:
/ip firewall connection print detail where protocol=tcp and reply-src-address=192.168.88.10 and reply-src-port=443
On versions that include the port in the address value, use /ip firewall connection print detail where protocol=tcp and reply-src-address="192.168.88.10:443" instead. Confirm the original client and WAN destination as well as the translated host and port before interpreting an entry.
The dstnat flag confirms destination NAT was applied; it does not prove that the host received or answered the packet. If the connection does not reach established, check the forwarding rules, the host’s default gateway and firewall profile (Windows on “Public”, ufw on Ubuntu), whether the service binds 127.0.0.1 instead of 0.0.0.0, and which VLAN it actually sits in.
Check 5: the ISP is in front of you
If nothing arrives on the WAN interface, look at the address on it:
/ip address print where interface=pppoe-out1
An address inside 100.64.0.0/10 is Shared Address Space, reserved by RFC 6598 for carrier-grade NAT. A 10.0.0.0/8 or 192.168.0.0/16 WAN address means an ISP modem in router mode, so you are double-NATed. Either way the SYN dies before your dst-nat rule can match it. Under CGNAT there is no fix on the MikroTik; the options are a static IP from the ISP, or a WireGuard tunnel to a small VPS that forwards the port down to you. The WireGuard configuration guide covers the RouterOS side, and the NAT traversal explainer covers why the tunnel works where the forward cannot. Under double NAT, bridge the modem or forward the port on it to the MikroTik’s WAN address. Some residential plans also block inbound TCP 25, 80 or 443; a non-standard port that works while 443 fails is the tell.
Check 6: stale connection tracking after an edit
MikroTik’s NAT documentation explains that existing connections retain their original NAT decision after a rule edit. Stop the test client’s retries and inspect the table before removing anything:
/ip firewall connection print detail where protocol=tcp
Identify the test client’s source address and port together with the original WAN destination and port 443. In split-field output, the destination port is dst-port; in combined output it is part of dst-address. An entry created before the correct NAT rule may lack the expected reply-src-address, so matching only the private host can miss the stale connection.
After confirming the exact record, use /ip firewall connection remove <entry-number> with its number from the inspected output. Reprint and recheck if the entry has expired or the listing has changed. Remove only the test connection you identified, then start a fresh client connection and repeat Check 4. Removing a tracked connection interrupts that session; leave unrelated entries in place.
If you run OPNsense elsewhere, the same failure classes exist under different names; the OPNsense port forward guide maps them to that platform’s reflection settings.
Things to test before you call it done
- From outside (LTE, not Wi-Fi):
nc -vz -w 5 <public-ip> 443ornmap -Pn -p 443 <public-ip>. “open” is the only pass. - From inside, using the public name:
curl -vk https://<hostname>/. This exercises hairpin or split DNS, whichever you chose. dig +short <hostname>must equal the address from/ip address print where interface=pppoe-out1. A stale dynamic DNS record looks exactly like a broken forward./ip firewall nat print statsbefore and after each external test; the dst-nat counter must increment per attempt.- Repeat the connection-table inspection in Check 4 during a test: confirm the original WAN destination, translated reply source,
dstnatflag and established state. - For UDP services, test with the real client;
nc -uproves nothing.
Leave the drop all from WAN not DSTNATed rule in place while testing. Disabling it to “see if the firewall is the problem” opens every LAN host to the internet. If you do it anyway, re-enable it before the next test.
Related across the network
- OPNsense Port Forwarding: NAT Rules That Actually Work — opnsenselab.com
- Best Homelab Firewall in 2026: OPNsense, pfSense, UniFi, MikroTik — firewallcompare.com
- pfSense Alternatives: 7 Platforms Compared for 2026 — firewallcompare.com
- OPNsense Firewall Rules and NAT: How They Work — opnsenserouter.com
- OPNsense WireGuard Not Connecting: Handshake Fixes — opnsenserouter.com