diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index fd675c9262..640d36c6be 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -802,6 +802,7 @@ mlx5_flow_ipool_create(struct mlx5_dev_ctx_shared *sh,
 	}
 }
 
+
 /**
  * Release the flow resources' indexed mempool.
  *
@@ -815,6 +816,9 @@ mlx5_flow_ipool_destroy(struct mlx5_dev_ctx_shared *sh)
 
 	for (i = 0; i < MLX5_IPOOL_MAX; ++i)
 		mlx5_ipool_destroy(sh->ipool[i]);
+	for (i = 0; i < MLX5_MAX_MODIFY_NUM; ++i)
+		if (sh->mdh_ipools[i])
+			mlx5_ipool_destroy(sh->mdh_ipools[i]);
 }
 
 /*
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index e9b08094a6..e7e4749824 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -36,6 +36,19 @@
 
 #define MLX5_SH(dev) (((struct mlx5_priv *)(dev)->data->dev_private)->sh)
 
+/*
+ * Number of modification commands.
+ * The maximal actions amount in FW is some constant, and it is 16 in the
+ * latest releases. In some old releases, it will be limited to 8.
+ * Since there is no interface to query the capacity, the maximal value should
+ * be used to allow PMD to create the flow. The validation will be done in the
+ * lower driver layer or FW. A failure will be returned if exceeds the maximal
+ * supported actions number on the root table.
+ * On non-root tables, there is no limitation, but 32 is enough right now.
+ */
+#define MLX5_MAX_MODIFY_NUM			32
+#define MLX5_ROOT_TBL_MODIFY_NUM		16
+
 enum mlx5_ipool_index {
 #if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H)
 	MLX5_IPOOL_DECAP_ENCAP = 0, /* Pool for encap/decap resource. */
@@ -1146,6 +1159,7 @@ struct mlx5_dev_ctx_shared {
 	struct mlx5_flow_counter_mng cmng; /* Counters management structure. */
 	void *default_miss_action; /* Default miss action. */
 	struct mlx5_indexed_pool *ipool[MLX5_IPOOL_MAX];
+	struct mlx5_indexed_pool *mdh_ipools[MLX5_MAX_MODIFY_NUM];
 	/* Memory Pool for mlx5 flow resources. */
 	struct mlx5_l3t_tbl *cnt_id_tbl; /* Shared counter lookup table. */
 	/* Shared interrupt handler section. */
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index e3a29297ba..7027012220 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -505,23 +505,11 @@ struct mlx5_flow_dv_tag_resource {
 	uint32_t tag_id; /**< Tag ID. */
 };
 
-/*
- * Number of modification commands.
- * The maximal actions amount in FW is some constant, and it is 16 in the
- * latest releases. In some old releases, it will be limited to 8.
- * Since there is no interface to query the capacity, the maximal value should
- * be used to allow PMD to create the flow. The validation will be done in the
- * lower driver layer or FW. A failure will be returned if exceeds the maximal
- * supported actions number on the root table.
- * On non-root tables, there is no limitation, but 32 is enough right now.
- */
-#define MLX5_MAX_MODIFY_NUM			32
-#define MLX5_ROOT_TBL_MODIFY_NUM		16
-
 /* Modify resource structure */
 struct mlx5_flow_dv_modify_hdr_resource {
 	struct mlx5_list_entry entry;
 	void *action; /**< Modify header action object. */
+	uint32_t idx;
 	/* Key area for hash list matching: */
 	uint8_t ft_type; /**< Flow table type, Rx or Tx. */
 	uint8_t actions_num; /**< Number of modification actions. */
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index 4b9fd22824..e39fe43854 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -5344,6 +5344,45 @@ flow_dv_modify_match_cb(void *tool_ctx __rte_unused,
 	       memcmp(&ref->ft_type, &resource->ft_type, key_len);
 }
 
+static struct mlx5_indexed_pool *
+flow_dv_modify_ipool_get(struct mlx5_dev_ctx_shared *sh, uint8_t index)
+{
+	struct mlx5_indexed_pool *ipool = __atomic_load_n
+				     (&sh->mdh_ipools[index], __ATOMIC_SEQ_CST);
+
+	if (!ipool) {
+		struct mlx5_indexed_pool *expected = NULL;
+		struct mlx5_indexed_pool_config cfg =
+		    (struct mlx5_indexed_pool_config) {
+		       .size = sizeof(struct mlx5_flow_dv_modify_hdr_resource) +
+								   (index + 1) *
+					   sizeof(struct mlx5_modification_cmd),
+		       .trunk_size = 64,
+		       .grow_trunk = 3,
+		       .grow_shift = 2,
+		       .need_lock = 1,
+		       .release_mem_en = 1,
+		       .malloc = mlx5_malloc,
+		       .free = mlx5_free,
+		       .type = "mlx5_modify_action_resource",
+		};
+
+		cfg.size = RTE_ALIGN(cfg.size, sizeof(ipool));
+		ipool = mlx5_ipool_create(&cfg);
+		if (!ipool)
+			return NULL;
+		if (!__atomic_compare_exchange_n(&sh->mdh_ipools[index],
+						 &expected, ipool, false,
+						 __ATOMIC_SEQ_CST,
+						 __ATOMIC_SEQ_CST)) {
+			mlx5_ipool_destroy(ipool);
+			ipool = __atomic_load_n(&sh->mdh_ipools[index],
+						__ATOMIC_SEQ_CST);
+		}
+	}
+	return ipool;
+}
+
 struct mlx5_list_entry *
 flow_dv_modify_create_cb(void *tool_ctx, void *cb_ctx)
 {
@@ -5352,12 +5391,20 @@ flow_dv_modify_create_cb(void *tool_ctx, void *cb_ctx)
 	struct mlx5dv_dr_domain *ns;
 	struct mlx5_flow_dv_modify_hdr_resource *entry;
 	struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data;
+	struct mlx5_indexed_pool *ipool = flow_dv_modify_ipool_get(sh,
+							  ref->actions_num - 1);
 	int ret;
 	uint32_t data_len = ref->actions_num * sizeof(ref->actions[0]);
 	uint32_t key_len = sizeof(*ref) - offsetof(typeof(*ref), ft_type);
+	uint32_t idx;
 
-	entry = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*entry) + data_len, 0,
-			    SOCKET_ID_ANY);
+	if (unlikely(!ipool)) {
+		rte_flow_error_set(ctx->error, ENOMEM,
+				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+				   NULL, "cannot allocate modify ipool");
+		return NULL;
+	}
+	entry = mlx5_ipool_zmalloc(ipool, &idx);
 	if (!entry) {
 		rte_flow_error_set(ctx->error, ENOMEM,
 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
@@ -5377,25 +5424,29 @@ flow_dv_modify_create_cb(void *tool_ctx, void *cb_ctx)
 					(sh->ctx, ns, entry,
 					 data_len, &entry->action);
 	if (ret) {
-		mlx5_free(entry);
+		mlx5_ipool_free(sh->mdh_ipools[ref->actions_num - 1], idx);
 		rte_flow_error_set(ctx->error, ENOMEM,
 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
 				   NULL, "cannot create modification action");
 		return NULL;
 	}
+	entry->idx = idx;
 	return &entry->entry;
 }
 
 struct mlx5_list_entry *
-flow_dv_modify_clone_cb(void *tool_ctx __rte_unused,
-			struct mlx5_list_entry *oentry, void *cb_ctx)
+flow_dv_modify_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry,
+			void *cb_ctx)
 {
+	struct mlx5_dev_ctx_shared *sh = tool_ctx;
 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
 	struct mlx5_flow_dv_modify_hdr_resource *entry;
 	struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data;
 	uint32_t data_len = ref->actions_num * sizeof(ref->actions[0]);
+	uint32_t idx;
 
-	entry = mlx5_malloc(0, sizeof(*entry) + data_len, 0, SOCKET_ID_ANY);
+	entry = mlx5_ipool_malloc(sh->mdh_ipools[ref->actions_num - 1],
+				  &idx);
 	if (!entry) {
 		rte_flow_error_set(ctx->error, ENOMEM,
 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
@@ -5403,14 +5454,18 @@ flow_dv_modify_clone_cb(void *tool_ctx __rte_unused,
 		return NULL;
 	}
 	memcpy(entry, oentry, sizeof(*entry) + data_len);
+	entry->idx = idx;
 	return &entry->entry;
 }
 
 void
-flow_dv_modify_clone_free_cb(void *tool_ctx __rte_unused,
-			     struct mlx5_list_entry *entry)
+flow_dv_modify_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
 {
-	mlx5_free(entry);
+	struct mlx5_dev_ctx_shared *sh = tool_ctx;
+	struct mlx5_flow_dv_modify_hdr_resource *res =
+		container_of(entry, typeof(*res), entry);
+
+	mlx5_ipool_free(sh->mdh_ipools[res->actions_num - 1], res->idx);
 }
 
 /**
@@ -13756,14 +13811,14 @@ flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev,
 }
 
 void
-flow_dv_modify_remove_cb(void *tool_ctx __rte_unused,
-			 struct mlx5_list_entry *entry)
+flow_dv_modify_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
 {
 	struct mlx5_flow_dv_modify_hdr_resource *res =
 		container_of(entry, typeof(*res), entry);
+	struct mlx5_dev_ctx_shared *sh = tool_ctx;
 
 	claim_zero(mlx5_flow_os_destroy_flow_action(res->action));
-	mlx5_free(entry);
+	mlx5_ipool_free(sh->mdh_ipools[res->actions_num - 1], res->idx);
 }
 
 /**
