diff --git a/drivers/net/mlx5/Makefile b/drivers/net/mlx5/Makefile
index ca1de9f..9097456 100644
--- a/drivers/net/mlx5/Makefile
+++ b/drivers/net/mlx5/Makefile
@@ -342,6 +342,16 @@ mlx5_autoconf.h.new: $(RTE_SDK)/buildtools/auto-config-h.sh
 		enum TCA_FLOWER_KEY_VLAN_ETH_TYPE \
 		$(AUTOCONF_OUTPUT)
 	$Q sh -- '$<' '$@' \
+		HAVE_TCA_FLOWER_KEY_TCP_FLAGS \
+		linux/pkt_cls.h \
+		enum TCA_FLOWER_KEY_TCP_FLAGS \
+		$(AUTOCONF_OUTPUT)
+	$Q sh -- '$<' '$@' \
+		HAVE_TCA_FLOWER_KEY_TCP_FLAGS_MASK \
+		linux/pkt_cls.h \
+		enum TCA_FLOWER_KEY_TCP_FLAGS_MASK \
+		$(AUTOCONF_OUTPUT)
+	$Q sh -- '$<' '$@' \
 		HAVE_TC_ACT_VLAN \
 		linux/tc_act/tc_vlan.h \
 		enum TCA_VLAN_PUSH_VLAN_PRIORITY \
diff --git a/drivers/net/mlx5/meson.build b/drivers/net/mlx5/meson.build
index fd93ac1..f562f30 100644
--- a/drivers/net/mlx5/meson.build
+++ b/drivers/net/mlx5/meson.build
@@ -180,6 +180,10 @@ if build
 		'TCA_FLOWER_KEY_VLAN_PRIO' ],
 		[ 'HAVE_TCA_FLOWER_KEY_VLAN_ETH_TYPE', 'linux/pkt_cls.h',
 		'TCA_FLOWER_KEY_VLAN_ETH_TYPE' ],
+		[ 'HAVE_TCA_FLOWER_KEY_TCP_FLAGS', 'linux/pkt_cls.h',
+		'TCA_FLOWER_KEY_TCP_FLAGS' ],
+		[ 'HAVE_TCA_FLOWER_KEY_TCP_FLAGS_MASK', 'linux/pkt_cls.h',
+		'TCA_FLOWER_KEY_TCP_FLAGS_MASK' ],
 		[ 'HAVE_TC_ACT_VLAN', 'linux/tc_act/tc_vlan.h',
 		'TCA_VLAN_PUSH_VLAN_PRIORITY' ],
 		[ 'HAVE_RDMA_NL_NLDEV', 'rdma/rdma_netlink.h',
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index ed60c40..74e7251 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -1226,6 +1226,8 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
  *   Bit-fields that holds the items detected until now.
  * @param[in] target_protocol
  *   The next protocol in the previous item.
+ * @param[in] flow_mask
+ *   mlx5 flow-specific (TCF, DV, verbs, etc.) supported header fields mask.
  * @param[out] error
  *   Pointer to error structure.
  *
@@ -1236,9 +1238,17 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 mlx5_flow_validate_item_tcp(const struct rte_flow_item *item,
 			    uint64_t item_flags,
 			    uint8_t target_protocol,
+			    const struct tcp_hdr *flow_mask,
 			    struct rte_flow_error *error)
 {
 	const struct rte_flow_item_tcp *mask = item->mask;
+	const struct tcp_hdr default_mask = {
+		.src_port = RTE_BE16(0xffff),
+		.dst_port = RTE_BE16(0xffff),
+	};
+	const struct rte_flow_item_tcp nic_mask = {
+		.hdr = flow_mask ? *flow_mask : default_mask,
+	};
 	const int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
 	int ret;
 
@@ -1261,7 +1271,7 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 		mask = &rte_flow_item_tcp_mask;
 	ret = mlx5_flow_item_acceptable
 		(item, (const uint8_t *)mask,
-		 (const uint8_t *)&rte_flow_item_tcp_mask,
+		 (const uint8_t *)&nic_mask,
 		 sizeof(struct rte_flow_item_tcp), error);
 	if (ret < 0)
 		return ret;
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 12de841..da114ca 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -314,6 +314,7 @@ int mlx5_flow_validate_item_mpls(const struct rte_flow_item *item,
 int mlx5_flow_validate_item_tcp(const struct rte_flow_item *item,
 				uint64_t item_flags,
 				uint8_t target_protocol,
+				const struct tcp_hdr *flow_mask,
 				struct rte_flow_error *error);
 int mlx5_flow_validate_item_udp(const struct rte_flow_item *item,
 				uint64_t item_flags,
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index 3bb462c..b878cc0 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -180,7 +180,8 @@
 			break;
 		case RTE_FLOW_ITEM_TYPE_TCP:
 			ret = mlx5_flow_validate_item_tcp(items, item_flags,
-							  next_protocol, error);
+							  next_protocol,
+							  NULL, error);
 			if (ret < 0)
 				return ret;
 			item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
diff --git a/drivers/net/mlx5/mlx5_flow_tcf.c b/drivers/net/mlx5/mlx5_flow_tcf.c
index 91f6ef6..22b23a4 100644
--- a/drivers/net/mlx5/mlx5_flow_tcf.c
+++ b/drivers/net/mlx5/mlx5_flow_tcf.c
@@ -148,6 +148,12 @@ struct tc_vlan {
 #ifndef HAVE_TCA_FLOWER_KEY_VLAN_ETH_TYPE
 #define TCA_FLOWER_KEY_VLAN_ETH_TYPE 25
 #endif
+#ifndef HAVE_TCA_FLOWER_KEY_TCP_FLAGS
+#define TCA_FLOWER_KEY_TCP_FLAGS 71
+#endif
+#ifndef HAVE_TCA_FLOWER_KEY_TCP_FLAGS_MASK
+#define TCA_FLOWER_KEY_TCP_FLAGS_MASK 72
+#endif
 
 #ifndef IPV6_ADDR_LEN
 #define IPV6_ADDR_LEN 16
@@ -204,6 +210,7 @@ struct tc_vlan {
 	.tcp.hdr = {
 		.src_port = RTE_BE16(0xffff),
 		.dst_port = RTE_BE16(0xffff),
+		.tcp_flags = 0xff,
 	},
 	.udp.hdr = {
 		.src_port = RTE_BE16(0xffff),
@@ -626,8 +633,11 @@ struct flow_tcf_ptoi {
 				return -rte_errno;
 			break;
 		case RTE_FLOW_ITEM_TYPE_TCP:
-			ret = mlx5_flow_validate_item_tcp(items, item_flags,
-							  next_protocol, error);
+			ret = mlx5_flow_validate_item_tcp
+					     (items, item_flags,
+					      next_protocol,
+					      &flow_tcf_mask_supported.tcp.hdr,
+					      error);
 			if (ret < 0)
 				return ret;
 			item_flags |= MLX5_FLOW_LAYER_OUTER_L4_TCP;
@@ -1289,6 +1299,18 @@ struct flow_tcf_ptoi {
 						 TCA_FLOWER_KEY_TCP_DST_MASK,
 						 mask.tcp->hdr.dst_port);
 			}
+			if (mask.tcp->hdr.tcp_flags) {
+				mnl_attr_put_u16
+					(nlh,
+					 TCA_FLOWER_KEY_TCP_FLAGS,
+					 rte_cpu_to_be_16
+						(spec.tcp->hdr.tcp_flags));
+				mnl_attr_put_u16
+					(nlh,
+					 TCA_FLOWER_KEY_TCP_FLAGS_MASK,
+					 rte_cpu_to_be_16
+						(mask.tcp->hdr.tcp_flags));
+			}
 			break;
 		default:
 			return rte_flow_error_set(error, ENOTSUP,
diff --git a/drivers/net/mlx5/mlx5_flow_verbs.c b/drivers/net/mlx5/mlx5_flow_verbs.c
index 6964476..3d68f8b 100644
--- a/drivers/net/mlx5/mlx5_flow_verbs.c
+++ b/drivers/net/mlx5/mlx5_flow_verbs.c
@@ -1057,7 +1057,8 @@
 			break;
 		case RTE_FLOW_ITEM_TYPE_TCP:
 			ret = mlx5_flow_validate_item_tcp(items, item_flags,
-							  next_protocol, error);
+							  next_protocol,
+							  NULL, error);
 			if (ret < 0)
 				return ret;
 			item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
