diff --git a/northd/northd.c b/northd/northd.c
index b264fb850b..23ab5ac260 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -6529,7 +6529,7 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows,
     ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB, 0, "1", "next;");
 
     if (has_stateful) {
-        /* Ingress and Egress ACL Table (Priority 1).
+        /* Ingress and Egress ACL Table (Priority 1 and 2).
          *
          * By default, traffic is allowed.  This is partially handled by
          * the Priority 0 ACL flows added earlier, but we also need to
@@ -6549,7 +6549,20 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows,
          * We need to set ct_label.blocked=0 to let the connection continue,
          * which will be done by ct_commit() in the "stateful" stage.
          * Subsequent packets will hit the flow at priority 0 that just
-         * uses "next;". */
+         * uses "next;".
+         *
+         * However, we don't want to commit if the packet was not sent to
+         * conntrack in the first place.
+         * Eg. if inport or outport is a router peer port. */
+        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 2,
+                      REGBIT_CONNTRACK_DEFRAG" == 0 && "
+                      REGBIT_CONNTRACK_NAT" == 0",
+                      "next;");
+        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 2,
+                      REGBIT_CONNTRACK_DEFRAG" == 0 && "
+                      REGBIT_CONNTRACK_NAT" == 0",
+                      "next;");
+
         ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 1,
                       "ip && (!ct.est || (ct.est && ct_label.blocked == 1))",
                        REGBIT_CONNTRACK_COMMIT" = 1; next;");
diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
index 4784bff041..d788efe70b 100644
--- a/northd/ovn-northd.8.xml
+++ b/northd/ovn-northd.8.xml
@@ -784,6 +784,12 @@
     </p>
 
     <ul>
+      <li>
+        A priority-2 flow that advances the packet to the next stage if the
+        packet was not sent to conntrack earlier, by matching on
+        <code>reg0[0] == 0 &amp;&amp; reg0[1] == 1</code>.
+      </li>
+
       <li>
         A priority-1 flow that sets the hint to commit IP traffic to the
         connection tracker (with action <code>reg0[1] = 1; next;</code>).  This
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index 60d91a7717..bfd0f2382b 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -2265,6 +2265,7 @@ AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e
   table=4 (ls_out_acl         ), priority=1    , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;)
   table=4 (ls_out_acl         ), priority=1001 , match=(reg0[[7]] == 1 && (ip)), action=(reg0[[1]] = 1; next;)
   table=4 (ls_out_acl         ), priority=1001 , match=(reg0[[8]] == 1 && (ip)), action=(next;)
+  table=4 (ls_out_acl         ), priority=2    , match=(reg0[[0]] == 0 && reg0[[2]] == 0), action=(next;)
   table=4 (ls_out_acl         ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;)
   table=4 (ls_out_acl         ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
   table=4 (ls_out_acl         ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;)
@@ -2282,6 +2283,7 @@ AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e
   table=9 (ls_in_acl          ), priority=1    , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;)
   table=9 (ls_in_acl          ), priority=1001 , match=(reg0[[7]] == 1 && (ip)), action=(reg0[[1]] = 1; next;)
   table=9 (ls_in_acl          ), priority=1001 , match=(reg0[[8]] == 1 && (ip)), action=(next;)
+  table=9 (ls_in_acl          ), priority=2    , match=(reg0[[0]] == 0 && reg0[[2]] == 0), action=(next;)
   table=9 (ls_in_acl          ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
   table=9 (ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
   table=9 (ls_in_acl          ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;)
@@ -6328,6 +6330,7 @@ AT_CAPTURE_FILE([lsflows])
 AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl
   table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_acl          ), priority=1    , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;)
+  table=??(ls_in_acl          ), priority=2    , match=(reg0[[0]] == 0 && reg0[[2]] == 0), action=(next;)
   table=??(ls_in_acl          ), priority=2001 , match=(reg0[[10]] == 1 && (ip4)), action=(ct_commit { ct_label.blocked = 1; }; /* drop */)
   table=??(ls_in_acl          ), priority=2001 , match=(reg0[[9]] == 1 && (ip4)), action=(/* drop */)
   table=??(ls_in_acl          ), priority=2002 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg0[[1]] = 1; next;)
@@ -6380,6 +6383,7 @@ AT_CAPTURE_FILE([lsflows])
 AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl
   table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_acl          ), priority=1    , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;)
+  table=??(ls_in_acl          ), priority=2    , match=(reg0[[0]] == 0 && reg0[[2]] == 0), action=(next;)
   table=??(ls_in_acl          ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
   table=??(ls_in_acl          ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
   table=??(ls_in_acl          ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;)
@@ -6432,6 +6436,7 @@ AT_CAPTURE_FILE([lsflows])
 AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl
   table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_acl          ), priority=1    , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;)
+  table=??(ls_in_acl          ), priority=2    , match=(reg0[[0]] == 0 && reg0[[2]] == 0), action=(next;)
   table=??(ls_in_acl          ), priority=2002 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg0[[1]] = 1; next;)
   table=??(ls_in_acl          ), priority=2002 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(next;)
   table=??(ls_in_acl          ), priority=2003 , match=(reg0[[7]] == 1 && (ip4 && icmp)), action=(reg0[[1]] = 1; next;)
