diff --git a/controller/binding.c b/controller/binding.c
index 248de5148..11e99911c 100644
--- a/controller/binding.c
+++ b/controller/binding.c
@@ -1273,7 +1273,7 @@ claim_lport(const struct sbrec_port_binding *pb,
                 }
                 set_pb_chassis_in_sbrec(pb, chassis_rec, true);
             } else {
-                if_status_mgr_claim_iface(if_mgr, pb, chassis_rec,
+                if_status_mgr_claim_iface(if_mgr, pb, chassis_rec, iface_rec,
                                           sb_readonly);
             }
             register_claim_timestamp(pb->logical_port, now);
@@ -1288,7 +1288,7 @@ claim_lport(const struct sbrec_port_binding *pb,
                     !smap_get_bool(&iface_rec->external_ids,
                                    OVN_INSTALLED_EXT_ID, false)) {
                     if_status_mgr_claim_iface(if_mgr, pb, chassis_rec,
-                                              sb_readonly);
+                                              iface_rec, sb_readonly);
                 }
             }
         }
diff --git a/controller/if-status.c b/controller/if-status.c
index 8503e5daa..2bff284d6 100644
--- a/controller/if-status.c
+++ b/controller/if-status.c
@@ -18,12 +18,14 @@
 #include "binding.h"
 #include "if-status.h"
 #include "ofctrl-seqno.h"
+#include "ovsport.h"
 #include "simap.h"
 
 #include "lib/hmapx.h"
 #include "lib/util.h"
 #include "timeval.h"
 #include "openvswitch/vlog.h"
+#include "lib/vswitch-idl.h"
 #include "lib/ovn-sb-idl.h"
 
 VLOG_DEFINE_THIS_MODULE(if_status);
@@ -181,6 +183,7 @@ struct ovs_iface {
                              * be fully programmed in OVS.  Only used in state
                              * OIF_INSTALL_FLOWS.
                              */
+    uint16_t mtu;           /* Extracted from OVS interface.mtu field. */
 };
 
 static uint64_t ifaces_usage;
@@ -205,9 +208,10 @@ struct if_status_mgr {
     uint32_t iface_seqno;
 };
 
-static struct ovs_iface *ovs_iface_create(struct if_status_mgr *,
-                                          const char *iface_id,
-                                          enum if_state );
+static struct ovs_iface *
+ovs_iface_create(struct if_status_mgr *, const char *iface_id,
+                 const struct ovsrec_interface *iface_rec,
+                 enum if_state);
 static void add_to_ovn_uninstall_hash(struct if_status_mgr *, const char *,
                                       const struct uuid *);
 static void ovs_iface_destroy(struct if_status_mgr *, struct ovs_iface *);
@@ -272,13 +276,14 @@ void
 if_status_mgr_claim_iface(struct if_status_mgr *mgr,
                           const struct sbrec_port_binding *pb,
                           const struct sbrec_chassis *chassis_rec,
+                          const struct ovsrec_interface *iface_rec,
                           bool sb_readonly)
 {
     const char *iface_id = pb->logical_port;
     struct ovs_iface *iface = shash_find_data(&mgr->ifaces, iface_id);
 
     if (!iface) {
-        iface = ovs_iface_create(mgr, iface_id, OIF_CLAIMED);
+        iface = ovs_iface_create(mgr, iface_id, iface_rec, OIF_CLAIMED);
     }
 
     memcpy(&iface->pb_uuid, &pb->header_.uuid, sizeof(iface->pb_uuid));
@@ -639,8 +644,34 @@ ovn_uninstall_hash_account_mem(const char *name, bool erase)
     }
 }
 
+uint16_t
+if_status_mgr_iface_get_mtu(const struct if_status_mgr *mgr,
+                            const char *iface_id)
+{
+    const struct ovs_iface *iface = shash_find_data(&mgr->ifaces, iface_id);
+    return iface ? iface->mtu : 0;
+}
+
+bool
+if_status_mgr_iface_update(const struct if_status_mgr *mgr,
+                           const struct ovsrec_interface *iface_rec)
+{
+    const char *iface_id = smap_get(&iface_rec->external_ids, "iface-id");
+    if (!iface_id) {
+        return false;
+    }
+    uint16_t mtu = get_iface_mtu(iface_rec);
+    struct ovs_iface *iface = shash_find_data(&mgr->ifaces, iface_id);
+    if (iface && iface->mtu != mtu) {
+        iface->mtu = mtu;
+        return true;
+    }
+    return false;
+}
+
 static struct ovs_iface *
 ovs_iface_create(struct if_status_mgr *mgr, const char *iface_id,
+                 const struct ovsrec_interface *iface_rec,
                  enum if_state state)
 {
     struct ovs_iface *iface = xzalloc(sizeof *iface);
@@ -650,6 +681,7 @@ ovs_iface_create(struct if_status_mgr *mgr, const char *iface_id,
     shash_add_nocopy(&mgr->ifaces, iface->id, iface);
     ovs_iface_set_state(mgr, iface, state);
     ovs_iface_account_mem(iface_id, false);
+    if_status_mgr_iface_update(mgr, iface_rec);
     return iface;
 }
 
diff --git a/controller/if-status.h b/controller/if-status.h
index 8ba80acd9..55979ece4 100644
--- a/controller/if-status.h
+++ b/controller/if-status.h
@@ -30,6 +30,7 @@ void if_status_mgr_destroy(struct if_status_mgr *);
 void if_status_mgr_claim_iface(struct if_status_mgr *,
                                const struct sbrec_port_binding *pb,
                                const struct sbrec_chassis *chassis_rec,
+                               const struct ovsrec_interface *iface_rec,
                                bool sb_readonly);
 void if_status_mgr_release_iface(struct if_status_mgr *, const char *iface_id);
 void if_status_mgr_delete_iface(struct if_status_mgr *, const char *iface_id);
@@ -56,5 +57,9 @@ bool if_status_handle_claims(struct if_status_mgr *mgr,
 void if_status_mgr_remove_ovn_installed(struct if_status_mgr *mgr,
                                         const char *name,
                                         const struct uuid *uuid);
+uint16_t if_status_mgr_iface_get_mtu(const struct if_status_mgr *mgr,
+                                     const char *iface_id);
+bool if_status_mgr_iface_update(const struct if_status_mgr *mgr,
+                                const struct ovsrec_interface *iface_rec);
 
 # endif /* controller/if-status.h */
diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
index 13a7d46ef..70c8623ce 100644
--- a/controller/ovn-controller.c
+++ b/controller/ovn-controller.c
@@ -60,6 +60,7 @@
 #include "lib/ovn-dirs.h"
 #include "lib/ovn-sb-idl.h"
 #include "lib/ovn-util.h"
+#include "ovsport.h"
 #include "patch.h"
 #include "vif-plug.h"
 #include "vif-plug-provider.h"
@@ -1060,6 +1061,7 @@ ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl)
     ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_name);
     ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_bfd);
     ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_bfd_status);
+    ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_mtu);
     ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_type);
     ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_options);
     ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_ofport);
@@ -1158,6 +1160,56 @@ en_ofctrl_is_connected_run(struct engine_node *node, void *data)
     engine_set_node_state(node, EN_UNCHANGED);
 }
 
+struct ed_type_if_status_mgr {
+    const struct if_status_mgr *manager;
+    const struct ovsrec_interface_table *iface_table;
+};
+
+static void *
+en_if_status_mgr_init(struct engine_node *node OVS_UNUSED,
+                      struct engine_arg *arg OVS_UNUSED)
+{
+    struct ed_type_if_status_mgr *data = xzalloc(sizeof *data);
+    return data;
+}
+
+static void
+en_if_status_mgr_cleanup(void *data OVS_UNUSED)
+{
+}
+
+static void
+en_if_status_mgr_run(struct engine_node *node, void *data_)
+{
+    enum engine_node_state state = EN_UNCHANGED;
+    struct ed_type_if_status_mgr *data = data_;
+    struct controller_engine_ctx *ctrl_ctx = engine_get_context()->client_ctx;
+    data->manager = ctrl_ctx->if_mgr;
+    data->iface_table = EN_OVSDB_GET(engine_get_input("OVS_interface", node));
+
+    const struct ovsrec_interface *iface;
+    OVSREC_INTERFACE_TABLE_FOR_EACH (iface, data->iface_table) {
+        if (if_status_mgr_iface_update(data->manager, iface)) {
+            state = EN_UPDATED;
+        }
+    }
+    engine_set_node_state(node, state);
+}
+
+static bool
+if_status_mgr_ovs_interface_handler(struct engine_node *node, void *data)
+{
+    struct ed_type_if_status_mgr *data_ = data;
+
+    const struct ovsrec_interface *iface;
+    OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface, data_->iface_table) {
+        if (if_status_mgr_iface_update(data_->manager, iface)) {
+            engine_set_node_state(node, EN_UPDATED);
+        }
+    }
+    return true;
+}
+
 /* This engine node is to wrap the OVS_interface input and maintain a copy of
  * the old version of data for the column external_ids.
  *
@@ -4056,6 +4108,9 @@ static void init_physical_ctx(struct engine_node *node,
     const struct ed_type_mff_ovn_geneve *ed_mff_ovn_geneve =
         engine_get_input_data("mff_ovn_geneve", node);
 
+    const struct ovsrec_interface_table *ovs_interface_table =
+        EN_OVSDB_GET(engine_get_input("if_status_mgr", node));
+
     const struct ovsrec_open_vswitch_table *ovs_table =
         EN_OVSDB_GET(engine_get_input("OVS_open_vswitch", node));
     const struct ovsrec_bridge_table *bridge_table =
@@ -4080,6 +4135,7 @@ static void init_physical_ctx(struct engine_node *node,
     p_ctx->sbrec_port_binding_by_name = sbrec_port_binding_by_name;
     p_ctx->sbrec_port_binding_by_datapath = sbrec_port_binding_by_datapath;
     p_ctx->port_binding_table = port_binding_table;
+    p_ctx->ovs_interface_table = ovs_interface_table;
     p_ctx->mc_group_table = multicast_group_table;
     p_ctx->br_int = br_int;
     p_ctx->chassis_table = chassis_table;
@@ -4093,6 +4149,9 @@ static void init_physical_ctx(struct engine_node *node,
     p_ctx->patch_ofports = &non_vif_data->patch_ofports;
     p_ctx->chassis_tunnels = &non_vif_data->chassis_tunnels;
 
+    struct controller_engine_ctx *ctrl_ctx = engine_get_context()->client_ctx;
+    p_ctx->if_mgr = ctrl_ctx->if_mgr;
+
     pflow_output_get_debug(node, &p_ctx->debug);
 }
 
@@ -4136,6 +4195,63 @@ en_pflow_output_run(struct engine_node *node, void *data)
     engine_set_node_state(node, EN_UPDATED);
 }
 
+static bool
+pflow_output_if_status_mgr_handler(struct engine_node *node,
+                                   void *data)
+{
+    struct ed_type_pflow_output *pfo = data;
+    struct ed_type_runtime_data *rt_data =
+        engine_get_input_data("runtime_data", node);
+    struct ed_type_non_vif_data *non_vif_data =
+        engine_get_input_data("non_vif_data", node);
+    struct ed_type_if_status_mgr *if_mgr_data =
+        engine_get_input_data("if_status_mgr", node);
+
+    struct physical_ctx p_ctx;
+    init_physical_ctx(node, rt_data, non_vif_data, &p_ctx);
+
+    const struct ovsrec_interface *iface;
+    OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface, if_mgr_data->iface_table) {
+        const char *iface_id = smap_get(&iface->external_ids, "iface-id");
+        if (!iface_id) {
+            continue;
+        }
+
+        const struct sbrec_port_binding *pb = lport_lookup_by_name(
+            p_ctx.sbrec_port_binding_by_name, iface_id);
+        if (!pb) {
+            continue;
+        }
+        if (pb->n_additional_chassis) {
+            /* Update flows for all ports in datapath. */
+            struct sbrec_port_binding *target =
+                sbrec_port_binding_index_init_row(
+                    p_ctx.sbrec_port_binding_by_datapath);
+            sbrec_port_binding_index_set_datapath(target, pb->datapath);
+
+            const struct sbrec_port_binding *binding;
+            SBREC_PORT_BINDING_FOR_EACH_EQUAL (
+                    binding, target, p_ctx.sbrec_port_binding_by_datapath) {
+                bool removed = sbrec_port_binding_is_deleted(binding);
+                if (!physical_handle_flows_for_lport(binding, removed, &p_ctx,
+                                                     &pfo->flow_table)) {
+                    return false;
+                }
+            }
+            sbrec_port_binding_index_destroy_row(target);
+        } else {
+            /* If any multichassis ports, update flows for the port. */
+            bool removed = sbrec_port_binding_is_deleted(pb);
+            if (!physical_handle_flows_for_lport(pb, removed, &p_ctx,
+                                                 &pfo->flow_table)) {
+                return false;
+            }
+        }
+        engine_set_node_state(node, EN_UPDATED);
+    }
+    return true;
+}
+
 static bool
 pflow_output_sb_port_binding_handler(struct engine_node *node,
                                      void *data)
@@ -4619,6 +4735,7 @@ main(int argc, char *argv[])
     ENGINE_NODE_WITH_CLEAR_TRACK_DATA(port_groups, "port_groups");
     ENGINE_NODE(northd_options, "northd_options");
     ENGINE_NODE(dhcp_options, "dhcp_options");
+    ENGINE_NODE(if_status_mgr, "if_status_mgr");
     ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lb_data, "lb_data");
 
 #define SB_NODE(NAME, NAME_STR) ENGINE_NODE_SB(NAME, NAME_STR);
@@ -4657,6 +4774,9 @@ main(int argc, char *argv[])
     engine_add_input(&en_non_vif_data, &en_ovs_interface,
                      non_vif_data_ovs_iface_handler);
 
+    engine_add_input(&en_if_status_mgr, &en_ovs_interface,
+                     if_status_mgr_ovs_interface_handler);
+
     /* Note: The order of inputs is important, all OVS interface changes must
      * be handled before any ct_zone changes.
      */
@@ -4667,6 +4787,8 @@ main(int argc, char *argv[])
     engine_add_input(&en_pflow_output, &en_sb_chassis,
                      pflow_lflow_output_sb_chassis_handler);
 
+    engine_add_input(&en_pflow_output, &en_if_status_mgr,
+                     pflow_output_if_status_mgr_handler);
     engine_add_input(&en_pflow_output, &en_sb_port_binding,
                      pflow_output_sb_port_binding_handler);
     engine_add_input(&en_pflow_output, &en_sb_multicast_group,
diff --git a/controller/ovsport.c b/controller/ovsport.c
index ec38c3fca..ebcb9cb6d 100644
--- a/controller/ovsport.c
+++ b/controller/ovsport.c
@@ -264,3 +264,12 @@ maintain_interface_smap_column(
         }
     }
 }
+
+uint16_t
+get_iface_mtu(const struct ovsrec_interface *iface)
+{
+    if (!iface || !iface->n_mtu || iface->mtu[0] <= 0) {
+        return 0;
+    }
+    return (uint16_t) iface->mtu[0];
+}
diff --git a/controller/ovsport.h b/controller/ovsport.h
index e355ff7ff..c40c1855a 100644
--- a/controller/ovsport.h
+++ b/controller/ovsport.h
@@ -57,4 +57,6 @@ const struct ovsrec_port * ovsport_lookup_by_interfaces(
 const struct ovsrec_port * ovsport_lookup_by_interface(
         struct ovsdb_idl_index *, struct ovsrec_interface *);
 
+uint16_t get_iface_mtu(const struct ovsrec_interface *);
+
 #endif /* lib/ovsport.h */
diff --git a/controller/physical.h b/controller/physical.h
index f450dca94..1f1ed55ef 100644
--- a/controller/physical.h
+++ b/controller/physical.h
@@ -52,11 +52,13 @@ struct physical_ctx {
     struct ovsdb_idl_index *sbrec_port_binding_by_name;
     struct ovsdb_idl_index *sbrec_port_binding_by_datapath;
     const struct sbrec_port_binding_table *port_binding_table;
+    const struct ovsrec_interface_table *ovs_interface_table;
     const struct sbrec_multicast_group_table *mc_group_table;
     const struct ovsrec_bridge *br_int;
     const struct sbrec_chassis_table *chassis_table;
     const struct sbrec_chassis *chassis;
     const struct sset *active_tunnels;
+    const struct if_status_mgr *if_mgr;
     struct hmap *local_datapaths;
     struct sset *local_lports;
     const struct simap *ct_zones;
