diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index 1141935..41be692 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -600,6 +600,7 @@ struct mlx5_priv {
 #endif
 	uint8_t skip_default_rss_reta; /* Skip configuration of default reta. */
 	uint8_t fdb_def_rule; /* Whether fdb jump to table 1 is configured. */
+	LIST_HEAD(fdir, mlx5_fdir_flow) fdir_flows; /* fdir flows. */
 };
 
 #define PORT_ID(priv) ((priv)->dev_data->port_id)
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 0d2e3df..007e5c4 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -4501,6 +4501,7 @@ struct rte_flow *
 		  struct rte_flow *flow)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_fdir_flow *priv_fdir_flow = NULL;
 
 	/*
 	 * Update RX queue flags only if port is started, otherwise it is
@@ -4515,7 +4516,17 @@ struct rte_flow *
 	if (list)
 		TAILQ_REMOVE(list, flow, next);
 	flow_mreg_del_copy_action(dev, flow);
-	rte_free(flow->fdir);
+	if (flow->fdir) {
+		LIST_FOREACH(priv_fdir_flow, &priv->fdir_flows, next) {
+			if (priv_fdir_flow->flow == flow)
+				break;
+		}
+		if (priv_fdir_flow) {
+			LIST_REMOVE(priv_fdir_flow, next);
+			rte_free(priv_fdir_flow->flow);
+			rte_free(priv_fdir_flow);
+		}
+	}
 	if (flow->idx)
 		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_RTE_FLOW],
 				flow->idx);
@@ -5211,12 +5222,14 @@ struct rte_flow *
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
 	struct rte_flow *flow = NULL;
+	struct mlx5_fdir_flow *priv_fdir_flow = NULL;
 
 	MLX5_ASSERT(fdir_flow);
-	TAILQ_FOREACH(flow, &priv->flows, next) {
-		if (flow->fdir && !flow_fdir_cmp(flow->fdir, fdir_flow)) {
+	LIST_FOREACH(priv_fdir_flow, &priv->fdir_flows, next) {
+		if (!flow_fdir_cmp(priv_fdir_flow->fdir, fdir_flow)) {
 			DRV_LOG(DEBUG, "port %u found FDIR flow %p",
 				dev->data->port_id, (void *)flow);
+			flow = priv_fdir_flow->flow;
 			break;
 		}
 	}
@@ -5241,6 +5254,7 @@ struct rte_flow *
 	struct mlx5_priv *priv = dev->data->dev_private;
 	struct mlx5_fdir *fdir_flow;
 	struct rte_flow *flow;
+	struct mlx5_fdir_flow *priv_fdir_flow = NULL;
 	int ret;
 
 	fdir_flow = rte_zmalloc(__func__, sizeof(*fdir_flow), 0);
@@ -5256,17 +5270,26 @@ struct rte_flow *
 		rte_errno = EEXIST;
 		goto error;
 	}
+	priv_fdir_flow = rte_zmalloc(__func__, sizeof(struct mlx5_fdir_flow),
+				     0);
+	if (!priv_fdir_flow) {
+		rte_errno = ENOMEM;
+		goto error;
+	}
 	flow = flow_list_create(dev, &priv->flows, &fdir_flow->attr,
 				fdir_flow->items, fdir_flow->actions, true,
 				NULL);
 	if (!flow)
 		goto error;
-	MLX5_ASSERT(!flow->fdir);
-	flow->fdir = fdir_flow;
+	flow->fdir = 1;
+	priv_fdir_flow->fdir = fdir_flow;
+	priv_fdir_flow->flow = flow;
+	LIST_INSERT_HEAD(&priv->fdir_flows, priv_fdir_flow, next);
 	DRV_LOG(DEBUG, "port %u created FDIR flow %p",
 		dev->data->port_id, (void *)flow);
 	return 0;
 error:
+	rte_free(priv_fdir_flow);
 	rte_free(fdir_flow);
 	return -rte_errno;
 }
@@ -5291,17 +5314,26 @@ struct rte_flow *
 	struct mlx5_fdir fdir_flow = {
 		.attr.group = 0,
 	};
+	struct mlx5_fdir_flow *priv_fdir_flow = NULL;
 	int ret;
 
 	ret = flow_fdir_filter_convert(dev, fdir_filter, &fdir_flow);
 	if (ret)
 		return -rte_errno;
-	flow = flow_fdir_filter_lookup(dev, &fdir_flow);
-	if (!flow) {
-		rte_errno = ENOENT;
-		return -rte_errno;
+	LIST_FOREACH(priv_fdir_flow, &priv->fdir_flows, next) {
+		/* Find the fdir in priv list */
+		if (!flow_fdir_cmp(priv_fdir_flow->fdir, &fdir_flow))
+			break;
 	}
+	if (!priv_fdir_flow)
+		return 0;
+	LIST_REMOVE(priv_fdir_flow, next);
+	flow = priv_fdir_flow->flow;
+	/* Fdir resource will be releasd after flow destroy. */
+	flow->fdir = 0;
 	flow_list_destroy(dev, &priv->flows, flow);
+	rte_free(priv_fdir_flow->fdir);
+	rte_free(priv_fdir_flow);
 	DRV_LOG(DEBUG, "port %u deleted FDIR flow %p",
 		dev->data->port_id, (void *)flow);
 	return 0;
@@ -5340,8 +5372,16 @@ struct rte_flow *
 flow_fdir_filter_flush(struct rte_eth_dev *dev)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-
-	mlx5_flow_list_flush(dev, &priv->flows, false);
+	struct mlx5_fdir_flow *priv_fdir_flow = NULL;
+
+	while (!LIST_EMPTY(&priv->fdir_flows)) {
+		priv_fdir_flow = LIST_FIRST(&priv->fdir_flows);
+		LIST_REMOVE(priv_fdir_flow, next);
+		priv_fdir_flow->flow->fdir = 0;
+		flow_list_destroy(dev, &priv->flows, priv_fdir_flow->flow);
+		rte_free(priv_fdir_flow->fdir);
+		rte_free(priv_fdir_flow);
+	}
 }
 
 /**
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 7611410..911007b 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -753,6 +753,13 @@ struct mlx5_flow_meter_profile {
 	uint32_t ref_cnt; /**< Use count. */
 };
 
+/* Fdir flow struture */
+struct mlx5_fdir_flow {
+	LIST_ENTRY(mlx5_fdir_flow) next; /* Pointer to the next element. */
+	struct mlx5_fdir *fdir; /* Pointer to fdir. */
+	struct rte_flow *flow; /* Pointer to flow. */
+};
+
 /* Flow structure. */
 struct rte_flow {
 	TAILQ_ENTRY(rte_flow) next; /**< Pointer to the next flow structure. */
@@ -764,7 +771,7 @@ struct rte_flow {
 	uint16_t meter; /**< Holds flow meter id. */
 	uint32_t dev_handles;
 	/**< Device flow handles that are part of the flow. */
-	struct mlx5_fdir *fdir; /**< Pointer to associated FDIR if any. */
+	uint32_t fdir:1; /**< Identifier of associated FDIR if any. */
 	uint32_t hairpin_flow_id; /**< The flow id used for hairpin. */
 	uint32_t copy_applied:1; /**< The MARK copy Flow os applied. */
 	uint32_t idx; /**< Index to the rte flow allocated from indexed pool. */
