diff --git a/lib/gro/gro_tcp.h b/lib/gro/gro_tcp.h
index d926c4b8cc..2c68b5f23e 100644
--- a/lib/gro/gro_tcp.h
+++ b/lib/gro/gro_tcp.h
@@ -19,6 +19,8 @@
 #define INVALID_TCP_HDRLEN(len) \
 	(((len) < sizeof(struct rte_tcp_hdr)) || ((len) > MAX_TCP_HLEN))
 
+#define VALID_GRO_TCP_FLAGS (RTE_TCP_ACK_FLAG | RTE_TCP_PSH_FLAG | RTE_TCP_FIN_FLAG)
+
 struct cmn_tcp_key {
 	struct rte_ether_addr eth_saddr;
 	struct rte_ether_addr eth_daddr;
@@ -81,11 +83,13 @@ merge_two_tcp_packets(struct gro_tcp_item *item,
 		struct rte_mbuf *pkt,
 		int cmp,
 		uint32_t sent_seq,
+		uint8_t tcp_flags,
 		uint16_t ip_id,
 		uint16_t l2_offset)
 {
 	struct rte_mbuf *pkt_head, *pkt_tail, *lastseg;
 	uint16_t hdr_len, l2_len;
+	struct rte_tcp_hdr *tcp_hdr;
 
 	if (cmp > 0) {
 		pkt_head = item->firstseg;
@@ -128,6 +132,11 @@ merge_two_tcp_packets(struct gro_tcp_item *item,
 	/* update MBUF metadata for the merged packet */
 	pkt_head->nb_segs += pkt_tail->nb_segs;
 	pkt_head->pkt_len += pkt_tail->pkt_len;
+	if (tcp_flags != RTE_TCP_ACK_FLAG) {
+		tcp_hdr = rte_pktmbuf_mtod_offset(pkt, struct rte_tcp_hdr *,
+						l2_offset + pkt_head->l2_len + pkt_head->l3_len);
+		tcp_hdr->tcp_flags |= tcp_flags;
+	}
 
 	return 1;
 }
diff --git a/lib/gro/gro_tcp4.c b/lib/gro/gro_tcp4.c
index 6645de592b..d426127dbd 100644
--- a/lib/gro/gro_tcp4.c
+++ b/lib/gro/gro_tcp4.c
@@ -126,6 +126,7 @@ gro_tcp4_reassemble(struct rte_mbuf *pkt,
 	uint32_t item_idx;
 	uint32_t i, max_flow_num, remaining_flow_num;
 	uint8_t find;
+	uint32_t item_start_idx;
 
 	/*
 	 * Don't process the packet whose TCP header length is greater
@@ -139,11 +140,8 @@ gro_tcp4_reassemble(struct rte_mbuf *pkt,
 	tcp_hdr = (struct rte_tcp_hdr *)((char *)ipv4_hdr + pkt->l3_len);
 	hdr_len = pkt->l2_len + pkt->l3_len + pkt->l4_len;
 
-	/*
-	 * Don't process the packet which has FIN, SYN, RST, PSH, URG, ECE
-	 * or CWR set.
-	 */
-	if (tcp_hdr->tcp_flags != RTE_TCP_ACK_FLAG)
+	/* Return early if the TCP flags are not handled in GRO layer */
+	if (tcp_hdr->tcp_flags & (~(VALID_GRO_TCP_FLAGS)))
 		return -1;
 
 	/* trim the tail padding bytes */
@@ -183,13 +181,36 @@ gro_tcp4_reassemble(struct rte_mbuf *pkt,
 		if (tbl->flows[i].start_index != INVALID_ARRAY_INDEX) {
 			if (is_same_tcp4_flow(tbl->flows[i].key, key)) {
 				find = 1;
+				item_start_idx = tbl->flows[i].start_index;
 				break;
 			}
 			remaining_flow_num--;
 		}
 	}
 
-	if (find == 0) {
+	if (find == 1) {
+		/*
+		 * Any packet with additional flags like PSH,FIN should be processed
+		 * and flushed immediately.
+		 * Hence marking the start time to 0, so that the packets will be flushed
+		 * immediately in timer mode.
+		 */
+		if (tcp_hdr->tcp_flags & (RTE_TCP_ACK_FLAG | RTE_TCP_PSH_FLAG | RTE_TCP_FIN_FLAG)) {
+			if (tcp_hdr->tcp_flags != RTE_TCP_ACK_FLAG)
+				tbl->items[item_start_idx].start_time = 0;
+			return process_tcp_item(pkt, tcp_hdr, tcp_dl, tbl->items,
+						tbl->flows[i].start_index,
+						&tbl->item_num, tbl->max_item_num,
+						ip_id, is_atomic, start_time);
+		} else {
+			return -1;
+		}
+	}
+	/*
+	 * Add new flow to the table only if contains ACK flag with data.
+	 * Do not add any packets with additional tcp flags to the GRO table
+	 */
+	if (tcp_hdr->tcp_flags == RTE_TCP_ACK_FLAG) {
 		sent_seq = rte_be_to_cpu_32(tcp_hdr->sent_seq);
 		item_idx = insert_new_tcp_item(pkt, tbl->items, &tbl->item_num,
 						tbl->max_item_num, start_time,
@@ -200,18 +221,19 @@ gro_tcp4_reassemble(struct rte_mbuf *pkt,
 		if (insert_new_flow(tbl, &key, item_idx) ==
 			INVALID_ARRAY_INDEX) {
 			/*
-			 * Fail to insert a new flow, so delete the
-			 * stored packet.
+			* Fail to insert a new flow, so delete the
+			* stored packet.
 			*/
-			delete_tcp_item(tbl->items, item_idx, &tbl->item_num, INVALID_ARRAY_INDEX);
+			delete_tcp_item(tbl->items, item_idx, &tbl->item_num,
+				INVALID_ARRAY_INDEX);
 			return -1;
 		}
 		return 0;
+	} else {
+		return -1;
 	}
 
-	return process_tcp_item(pkt, tcp_hdr, tcp_dl, tbl->items, tbl->flows[i].start_index,
-						&tbl->item_num, tbl->max_item_num,
-						ip_id, is_atomic, start_time);
+	return -1;
 }
 
 /*
diff --git a/lib/gro/gro_tcp_internal.h b/lib/gro/gro_tcp_internal.h
index cc84abeaeb..e4855da1ad 100644
--- a/lib/gro/gro_tcp_internal.h
+++ b/lib/gro/gro_tcp_internal.h
@@ -101,7 +101,7 @@ process_tcp_item(struct rte_mbuf *pkt,
 				is_atomic);
 		if (cmp) {
 			if (merge_two_tcp_packets(&items[cur_idx],
-						pkt, cmp, sent_seq, ip_id, 0))
+						pkt, cmp, sent_seq, tcp_hdr->tcp_flags, ip_id, 0))
 				return 1;
 			/*
 			 * Fail to merge the two packets, as the packet
diff --git a/lib/gro/gro_vxlan_tcp4.c b/lib/gro/gro_vxlan_tcp4.c
index 6ab7001922..8dd62a949c 100644
--- a/lib/gro/gro_vxlan_tcp4.c
+++ b/lib/gro/gro_vxlan_tcp4.c
@@ -239,10 +239,11 @@ merge_two_vxlan_tcp4_packets(struct gro_vxlan_tcp4_item *item,
 		struct rte_mbuf *pkt,
 		int cmp,
 		uint32_t sent_seq,
+		uint8_t tcp_flags,
 		uint16_t outer_ip_id,
 		uint16_t ip_id)
 {
-	if (merge_two_tcp_packets(&item->inner_item, pkt, cmp, sent_seq,
+	if (merge_two_tcp_packets(&item->inner_item, pkt, cmp, sent_seq, tcp_flags,
 				ip_id, pkt->outer_l2_len +
 				pkt->outer_l3_len)) {
 		/* Update the outer IPv4 ID to the large value. */
@@ -413,7 +414,7 @@ gro_vxlan_tcp4_reassemble(struct rte_mbuf *pkt,
 				tcp_dl, outer_is_atomic, is_atomic);
 		if (cmp) {
 			if (merge_two_vxlan_tcp4_packets(&(tbl->items[cur_idx]),
-						pkt, cmp, sent_seq,
+						pkt, cmp, sent_seq, tcp_hdr->tcp_flags,
 						outer_ip_id, ip_id))
 				return 1;
 			/*
