diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index c9f7179c3b4c..878fe5933d1a 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -9689,6 +9689,7 @@ const struct dpif_class dpif_netdev_class = {
     dpif_netdev_meter_set,
     dpif_netdev_meter_get,
     dpif_netdev_meter_del,
+    NULL,
     dpif_netdev_bond_add,
     dpif_netdev_bond_del,
     dpif_netdev_bond_stats_get,
diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
index 026b0daa8d83..8b95912aea97 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -25,6 +25,7 @@
 #include <net/if.h>
 #include <linux/types.h>
 #include <linux/pkt_sched.h>
+#include <linux/rtnetlink.h>
 #include <poll.h>
 #include <stdlib.h>
 #include <strings.h>
@@ -37,6 +38,7 @@
 #include "dpif-provider.h"
 #include "fat-rwlock.h"
 #include "flow.h"
+#include "id-pool.h"
 #include "netdev-linux.h"
 #include "netdev-offload.h"
 #include "netdev-provider.h"
@@ -61,6 +63,7 @@
 #include "packets.h"
 #include "random.h"
 #include "sset.h"
+#include "tc.h"
 #include "timeval.h"
 #include "unaligned.h"
 #include "util.h"
@@ -4363,12 +4366,32 @@ dpif_netlink_meter_del(struct dpif *dpif, ofproto_meter_id meter_id,
     err  = dpif_netlink_meter_get_stats(dpif, meter_id, stats,
                                         max_bands, OVS_METER_CMD_DEL);
     if (!err && netdev_is_flow_api_enabled()) {
-        meter_offload_del(meter_id, stats);
+        return meter_offload_del(meter_id, stats);
     }
 
     return err;
 }
 
+static void
+dpif_netlink_meter_revalidate(struct dpif *dpif_ OVS_UNUSED,
+                              struct hmap *meter_map)
+{
+    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+    ofproto_meter_id meter_id;
+    struct id_node *id_node;
+
+    HMAP_FOR_EACH_POP (id_node, node, meter_map) {
+        meter_id.uint32 = id_node->id;
+
+        if (meter_offload_del(meter_id, NULL) == EPERM) {
+            id_hmap_add(meter_map, meter_id.uint32);
+        } else {
+            VLOG_DBG_RL(&rl, "Delete meter %u in datapath success",
+                        meter_id.uint32);
+        }
+    }
+}
+
 static bool
 probe_broken_meters__(struct dpif *dpif)
 {
@@ -4588,6 +4611,7 @@ const struct dpif_class dpif_netlink_class = {
     dpif_netlink_meter_set,
     dpif_netlink_meter_get,
     dpif_netlink_meter_del,
+    dpif_netlink_meter_revalidate,
     NULL,                       /* bond_add */
     NULL,                       /* bond_del */
     NULL,                       /* bond_stats_get */
diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
index 12477a24feee..794fbc21686a 100644
--- a/lib/dpif-provider.h
+++ b/lib/dpif-provider.h
@@ -631,6 +631,10 @@ struct dpif_class {
     int (*meter_del)(struct dpif *, ofproto_meter_id meter_id,
                      struct ofputil_meter_stats *, uint16_t n_bands);
 
+    /* Checks unneeded meters from 'dpif' and removes them. They may
+     * be caused by deleting in-use meters. */
+    void (*meter_revalidate)(struct dpif *, struct hmap *meter_map);
+
     /* Adds a bond with 'bond_id' and the member-map to 'dpif'. */
     int (*bond_add)(struct dpif *dpif, uint32_t bond_id,
                     odp_port_t *member_map);
diff --git a/lib/dpif.c b/lib/dpif.c
index fe4db83fbfee..c8718239117d 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -2028,6 +2028,13 @@ dpif_meter_del(struct dpif *dpif, ofproto_meter_id meter_id,
     return error;
 }
 
+void
+dpif_meter_revalidate(struct dpif *dpif, struct hmap *meter_map){
+    if (dpif->dpif_class->meter_revalidate) {
+        dpif->dpif_class->meter_revalidate(dpif, meter_map);
+    }
+}
+
 int
 dpif_bond_add(struct dpif *dpif, uint32_t bond_id, odp_port_t *member_map)
 {
diff --git a/lib/dpif.h b/lib/dpif.h
index 6cb4dae6d8d7..e181e4ee1d6c 100644
--- a/lib/dpif.h
+++ b/lib/dpif.h
@@ -378,6 +378,7 @@
 
 #include "dpdk.h"
 #include "dp-packet.h"
+#include "id-pool.h"
 #include "netdev.h"
 #include "openflow/openflow.h"
 #include "openvswitch/ofp-meter.h"
@@ -905,6 +906,7 @@ int dpif_meter_get(const struct dpif *, ofproto_meter_id meter_id,
                    struct ofputil_meter_stats *, uint16_t n_bands);
 int dpif_meter_del(struct dpif *, ofproto_meter_id meter_id,
                    struct ofputil_meter_stats *, uint16_t n_bands);
+void dpif_meter_revalidate(struct dpif *dpif, struct hmap *meter_map);
 
 /* Bonding. */
 
diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c
index 15d1c36aa04e..f87a5e05e202 100644
--- a/lib/netdev-offload-tc.c
+++ b/lib/netdev-offload-tc.c
@@ -2980,8 +2980,11 @@ meter_tc_del_policer(ofproto_meter_id meter_id,
                         police_index, meter_id.uint32, ovs_strerror(err));
         } else {
             meter_free_police_index(police_index);
+            /* Do not remove the mapping between meter_id and police_index
+             * until this meter is deleted successfully in datapath. This
+             * mapping will be used in meter deletion in revalidator. */
+            meter_id_remove(meter_id.uint32);
         }
-        meter_id_remove(meter_id.uint32);
     }
 
     return err;
diff --git a/lib/netdev-offload.c b/lib/netdev-offload.c
index 4592262bd34e..0769f796e5b7 100644
--- a/lib/netdev-offload.c
+++ b/lib/netdev-offload.c
@@ -241,19 +241,21 @@ int
 meter_offload_del(ofproto_meter_id meter_id, struct ofputil_meter_stats *stats)
 {
     struct netdev_registered_flow_api *rfa;
+    int ret = 0;
 
     CMAP_FOR_EACH (rfa, cmap_node, &netdev_flow_apis) {
         if (rfa->flow_api->meter_del) {
-            int ret = rfa->flow_api->meter_del(meter_id, stats);
-            if (ret) {
+            int err = rfa->flow_api->meter_del(meter_id, stats);
+            if (err) {
                 VLOG_DBG_RL(&rl, "Failed deleting meter %u for flow api %s, "
                             "error %d", meter_id.uint32, rfa->flow_api->type,
                             ret);
+                ret = err;
             }
         }
     }
 
-    return 0;
+    return ret;
 }
 
 int
diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
index 31ac02d116fc..b802c9c7f13a 100644
--- a/ofproto/ofproto-dpif-upcall.c
+++ b/ofproto/ofproto-dpif-upcall.c
@@ -2828,6 +2828,12 @@ revalidate(struct revalidator *revalidator)
         }
         ovsrcu_quiesce();
     }
+    /* When fail_meter_hmap is not empty, revalidate to delete meters in this
+     * hashmap. */
+    if (hmap_count(&udpif->backer->fail_meter_hmap)) {
+        dpif_meter_revalidate(udpif->dpif, &udpif->backer->fail_meter_hmap);
+    }
+
     dpif_flow_dump_thread_destroy(dump_thread);
     ofpbuf_uninit(&odp_actions);
 }
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index f87e27a8cd7f..591af5503765 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -835,6 +835,7 @@ open_dpif_backer(const char *type, struct dpif_backer **backerp)
     dpif_meter_get_features(backer->dpif, &features);
     if (features.max_meters) {
         backer->meter_ids = id_pool_create(0, features.max_meters);
+        hmap_init(&backer->fail_meter_hmap);
     } else {
         backer->meter_ids = NULL;
     }
@@ -6790,8 +6791,15 @@ static void
 free_meter_id(struct free_meter_id_args *args)
 {
     struct ofproto_dpif *ofproto = args->ofproto;
+    int err;
+
+    err = dpif_meter_del(ofproto->backer->dpif, args->meter_id, NULL, 0);
+    /* Add fail deleted meter to fail_meter_hmap and waiting to be deleted in
+     * revalidator. */
+    if (err == EPERM) {
+        id_hmap_add(&ofproto->backer->fail_meter_hmap, args->meter_id.uint32);
+    }
 
-    dpif_meter_del(ofproto->backer->dpif, args->meter_id, NULL, 0);
     id_pool_free_id(ofproto->backer->meter_ids, args->meter_id.uint32);
     free(args);
 }
diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h
index d8e0cd37ac5b..befc68d13baa 100644
--- a/ofproto/ofproto-dpif.h
+++ b/ofproto/ofproto-dpif.h
@@ -61,6 +61,7 @@ struct ofproto_dpif;
 struct uuid;
 struct xlate_cache;
 struct xlate_ctx;
+struct id_pool;
 
 /* Number of implemented OpenFlow tables. */
 enum { N_TABLES = 255 };
@@ -260,6 +261,8 @@ struct dpif_backer {
 
     /* Meter. */
     struct id_pool *meter_ids;     /* Datapath meter allocation. */
+    struct hmap fail_meter_hmap;   /* Hashmap for meter with failed deletion
+                                    * in datapath */
 
     /* Connection tracking. */
     struct id_pool *tp_ids;             /* Datapath timeout policy id
