diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp
index 6f56f2e5..3513b7ac 100644
--- a/libi2pd/ECIESX25519AEADRatchetSession.cpp
+++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp
@@ -117,6 +117,12 @@ namespace garlic
 		return session->HandleNextMessage (buf, len, shared_from_this (), index);
 	}
 
+	bool ReceiveRatchetTagSet::IsSessionTerminated () const 
+	{ 
+		return !m_Session || m_Session->IsTerminated (); 
+	}
+
+	
 	SymmetricKeyTagSet::SymmetricKeyTagSet (GarlicDestination * destination, const uint8_t * key):
 		ReceiveRatchetTagSet (nullptr), m_Destination (destination)
 	{
diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h
index 517833e8..030e2c45 100644
--- a/libi2pd/ECIESX25519AEADRatchetSession.h
+++ b/libi2pd/ECIESX25519AEADRatchetSession.h
@@ -86,7 +86,8 @@ namespace garlic
 
 			virtual bool IsIndexExpired (int index) const;
 			virtual bool HandleNextMessage (uint8_t * buf, size_t len, int index);
-
+			virtual bool IsSessionTerminated () const;
+			
 		private:
 
 			int m_TrimBehindIndex = 0;
@@ -101,9 +102,10 @@ namespace garlic
 
 			SymmetricKeyTagSet (GarlicDestination * destination, const uint8_t * key);
 
-			bool IsIndexExpired (int index) const { return false; };
-			bool HandleNextMessage (uint8_t * buf, size_t len, int index);
-
+			bool IsIndexExpired (int index) const override { return false; };
+			bool HandleNextMessage (uint8_t * buf, size_t len, int index) override;
+			bool IsSessionTerminated () const override { return false; }
+			
 		private:
 
 			GarlicDestination * m_Destination;
diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp
index 7157052c..ba35995f 100644
--- a/libi2pd/Garlic.cpp
+++ b/libi2pd/Garlic.cpp
@@ -431,7 +431,8 @@ namespace garlic
 	}
 
 	GarlicDestination::GarlicDestination (): m_NumTags (32), // 32 tags by default
-		m_PayloadBuffer (nullptr), m_NumRatchetInboundTags (0) // 0 means standard
+		m_PayloadBuffer (nullptr), m_NumRatchetInboundTags (0), // 0 means standard
+		m_NumUsedECIESx25519Tags (0)
 	{
 	}
 
@@ -599,6 +600,7 @@ namespace garlic
 				LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message");
 				m_ECIESx25519Tags.erase (it);
 			}	
+			m_NumUsedECIESx25519Tags++;
 			return true;
 		}
 		return false;
@@ -883,24 +885,41 @@ namespace garlic
 		}
 
 		numExpiredTags = 0;
-		for (auto it = m_ECIESx25519Tags.begin (); it != m_ECIESx25519Tags.end ();)
+		if (m_NumUsedECIESx25519Tags > ECIESX25519_TAGSET_MAX_NUM_TAGS) // too many used tags
 		{
-			if (!it->second.tagset)
+			std::unordered_map<uint64_t, ECIESX25519AEADRatchetIndexTagset> oldTags;
+			std::swap (m_ECIESx25519Tags, oldTags); // re-create
+			for (auto& it: oldTags)
+				if (it.second.tagset)
+				{
+					if (it.second.tagset->IsExpired (ts) || it.second.tagset->IsIndexExpired (it.second.index))
+					{
+						it.second.tagset->DeleteSymmKey (it.second.index);
+						numExpiredTags++;
+					}
+					else if (it.second.tagset->IsSessionTerminated())
+						numExpiredTags++;
+					else
+						m_ECIESx25519Tags.emplace (it);	
+				}
+		}
+		else
+		{	
+			for (auto it = m_ECIESx25519Tags.begin (); it != m_ECIESx25519Tags.end ();)
 			{
-				// delete used tag
-				it = m_ECIESx25519Tags.erase (it);
-				continue;
-			}	
-			if (it->second.tagset->IsExpired (ts) || it->second.tagset->IsIndexExpired (it->second.index))
-			{
-				it->second.tagset->DeleteSymmKey (it->second.index);
-				it = m_ECIESx25519Tags.erase (it);
-				numExpiredTags++;
-			}
-			else
-			{
-				auto session = it->second.tagset->GetSession ();
-				if (!session || session->IsTerminated())
+				if (!it->second.tagset)
+				{
+					// delete used tag
+					it = m_ECIESx25519Tags.erase (it);
+					continue;
+				}	
+				if (it->second.tagset->IsExpired (ts) || it->second.tagset->IsIndexExpired (it->second.index))
+				{
+					it->second.tagset->DeleteSymmKey (it->second.index);
+					it = m_ECIESx25519Tags.erase (it);
+					numExpiredTags++;
+				}
+				else if (it->second.tagset->IsSessionTerminated())
 				{
 					it = m_ECIESx25519Tags.erase (it);
 					numExpiredTags++;
@@ -908,7 +927,8 @@ namespace garlic
 				else
 					++it;
 			}
-		}
+		}	
+		m_NumUsedECIESx25519Tags = 0;
 		if (numExpiredTags > 0)
 			LogPrint (eLogDebug, "Garlic: ", numExpiredTags, " ECIESx25519 tags expired for ", GetIdentHash().ToBase64 ());
 		if (m_LastTagset && m_LastTagset->IsExpired (ts))
diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h
index 83e3b050..0386752b 100644
--- a/libi2pd/Garlic.h
+++ b/libi2pd/Garlic.h
@@ -291,6 +291,7 @@ namespace garlic
 			std::unordered_map<SessionTag, std::shared_ptr<AESDecryption>, std::hash<i2p::data::Tag<32> > > m_Tags;
 			std::unordered_map<uint64_t, ECIESX25519AEADRatchetIndexTagset> m_ECIESx25519Tags; // session tag -> session
 			ReceiveRatchetTagSetPtr m_LastTagset; // tagset last message came for
+			int m_NumUsedECIESx25519Tags;
 			// DeliveryStatus
 			std::mutex m_DeliveryStatusSessionsMutex;
 			std::unordered_map<uint32_t, GarlicRoutingSessionPtr> m_DeliveryStatusSessions; // msgID -> session
@@ -299,7 +300,7 @@ namespace garlic
 
 			// for HTTP only
 			size_t GetNumIncomingTags () const { return m_Tags.size (); }
-			size_t GetNumIncomingECIESx25519Tags () const { return m_ECIESx25519Tags.size (); }
+			size_t GetNumIncomingECIESx25519Tags () const { return m_ECIESx25519Tags.size () - m_NumUsedECIESx25519Tags; }
 			const decltype(m_Sessions)& GetSessions () const { return m_Sessions; };
 			const decltype(m_ECIESx25519Sessions)& GetECIESx25519Sessions () const { return m_ECIESx25519Sessions; }
 	};