diff --git a/Sources/XXDatabase/Models/GroupChatInfo+GRDB.swift b/Sources/XXDatabase/Models/GroupChatInfo+GRDB.swift
index f8a549e06863143cc0829f0b7e2bc767d733ff4a..20062ab25781e6b59a9d4cb8b4d1ab3480d72ee9 100644
--- a/Sources/XXDatabase/Models/GroupChatInfo+GRDB.swift
+++ b/Sources/XXDatabase/Models/GroupChatInfo+GRDB.swift
@@ -9,6 +9,7 @@ extension GroupChatInfo: FetchableRecord {
   }
 
   static func request(_ query: Query) -> AdaptedFetchRequest<SQLRequest<GroupChatInfo>> {
+    var sqlJoins: [String] = ["INNER JOIN groups g ON g.id = m.groupId"]
     var sqlWhere: [String] = []
     var sqlArguments: StatementArguments = [:]
 
@@ -17,6 +18,21 @@ extension GroupChatInfo: FetchableRecord {
       _ = sqlArguments.append(contentsOf: sqlArgumentsAuthStatus(authStatus))
     }
 
+    if query.excludeBlockedContacts || query.excludeBannedContacts {
+      sqlJoins.append("INNER JOIN contacts l ON g.leaderId = l.id")
+      sqlJoins.append("INNER JOIN contacts s ON m.senderId = s.id")
+
+      if query.excludeBlockedContacts {
+        sqlWhere.append("l.isBlocked != 1")
+        sqlWhere.append("s.isBlocked != 1")
+      }
+
+      if query.excludeBannedContacts {
+        sqlWhere.append("l.isBanned != 1")
+        sqlWhere.append("s.isBanned != 1")
+      }
+    }
+
     let sql = """
       SELECT
         -- All group columns:
@@ -29,9 +45,8 @@ extension GroupChatInfo: FetchableRecord {
         MAX(m.date) AS date
       FROM
         messages m
-      INNER JOIN groups g
-        ON g.id = m.groupId
-      \(sqlWhere.isEmpty ? "" : "WHERE\n  \(sqlWhere.joined(separator: "\n  "))")
+      \(sqlJoins.joined(separator: "\n"))
+      \(sqlWhere.isEmpty ? "" : "WHERE\n  \(sqlWhere.joined(separator: "\n  AND "))")
       GROUP BY
         g.id
       ORDER BY
diff --git a/Sources/XXModels/Models/GroupChatInfo.swift b/Sources/XXModels/Models/GroupChatInfo.swift
index a9db76634871e70b6fa6ffd9e7ce84a4d52b39a2..8e92eddeeb155550a8659bbd7c3ab0b7f3f01206 100644
--- a/Sources/XXModels/Models/GroupChatInfo.swift
+++ b/Sources/XXModels/Models/GroupChatInfo.swift
@@ -49,10 +49,18 @@ extension GroupChatInfo {
     ///   - authStatus: Filter groups by auth status.
     ///     If set, only groups with any of the provided auth statuses will be included.
     ///     If `nil`, the filter is not used.
+    ///   - excludeBlockedContacts: Exclude groups with blocked leaders and last messages from
+    ///     blocked contacts (defaults to `false`).
+    ///   - excludeBannedContacts: Exclude groups with banned leaders and last messages from
+    ///     banned contacts (defaults to `false`).
     public init(
-      authStatus: Set<Group.AuthStatus>? = nil
+      authStatus: Set<Group.AuthStatus>? = nil,
+      excludeBlockedContacts: Bool = false,
+      excludeBannedContacts: Bool = false
     ) {
       self.authStatus = authStatus
+      self.excludeBlockedContacts = excludeBlockedContacts
+      self.excludeBannedContacts = excludeBannedContacts
     }
 
     /// Filter groups by auth status
@@ -60,5 +68,11 @@ extension GroupChatInfo {
     /// If set, only groups with any of the provided auth statuses will be included.
     /// If `nil`, the filter is not used.
     public var authStatus: Set<Group.AuthStatus>?
+
+    /// Exclude groups with blocked leaders and last messages from blocked contacts.
+    public var excludeBlockedContacts: Bool
+
+    /// Exclude groups with banned leaders and last messages from banned contacts.
+    public var excludeBannedContacts: Bool
   }
 }
diff --git a/Tests/XXDatabaseTests/GroupChatInfo+GRDBTests.swift b/Tests/XXDatabaseTests/GroupChatInfo+GRDBTests.swift
index ffc5c4a82a27b43e3e0541c59acdbc3a8b38c3c5..fd67cc0c6ae9d01815f7ab8fe8a48f6269884c59 100644
--- a/Tests/XXDatabaseTests/GroupChatInfo+GRDBTests.swift
+++ b/Tests/XXDatabaseTests/GroupChatInfo+GRDBTests.swift
@@ -139,4 +139,240 @@ final class GroupChatInfoGRDBTests: XCTestCase {
       ]
     )
   }
+
+  func testExcludeMessagesFromBlockedContacts() throws {
+    // Mock up contacts:
+
+    let contactA = try db.saveContact(.stub("A"))
+    let contactB = try db.saveContact(.stub("B"))
+    let contactC = try db.saveContact(.stub("C").withBlocked(true))
+
+    // Mock up groups:
+
+    let groupA = try db.saveGroup(.stub(
+      "A",
+      leaderId: contactA.id,
+      createdAt: .stub(1)
+    ))
+
+    try db.saveGroupMember(GroupMember(groupId: groupA.id, contactId: contactA.id))
+    try db.saveGroupMember(GroupMember(groupId: groupA.id, contactId: contactB.id))
+    try db.saveGroupMember(GroupMember(groupId: groupA.id, contactId: contactC.id))
+
+    let groupB = try db.saveGroup(.stub(
+      "B",
+      leaderId: contactB.id,
+      createdAt: .stub(2)
+    ))
+
+    try db.saveGroupMember(GroupMember(groupId: groupB.id, contactId: contactA.id))
+    try db.saveGroupMember(GroupMember(groupId: groupB.id, contactId: contactB.id))
+    try db.saveGroupMember(GroupMember(groupId: groupB.id, contactId: contactC.id))
+
+    let groupC = try db.saveGroup(.stub(
+      "C",
+      leaderId: contactC.id,
+      createdAt: .stub(3)
+    ))
+
+    try db.saveGroupMember(GroupMember(groupId: groupC.id, contactId: contactA.id))
+    try db.saveGroupMember(GroupMember(groupId: groupC.id, contactId: contactB.id))
+    try db.saveGroupMember(GroupMember(groupId: groupC.id, contactId: contactC.id))
+
+    // Mock up messages in group A:
+
+    try db.saveMessage(.stub(
+      from: contactA,
+      to: groupA,
+      at: 1,
+      isUnread: true
+    ))
+
+    let groupA_message_fromB_at2 = try db.saveMessage(.stub(
+      from: contactB,
+      to: groupA,
+      at: 2,
+      isUnread: true
+    ))
+
+    let groupA_message_fromC_at3 = try db.saveMessage(.stub(
+      from: contactC,
+      to: groupA,
+      at: 3,
+      isUnread: true
+    ))
+
+    // Mock up messages in group B:
+
+    let groupB_message_fromC_at4 = try db.saveMessage(.stub(
+      from: contactC,
+      to: groupB,
+      at: 4,
+      isUnread: true
+    ))
+
+    // Mock up messages in group C:
+
+    try db.saveMessage(.stub(
+      from: contactA,
+      to: groupC,
+      at: 5,
+      isUnread: true
+    ))
+
+    let groupC_message_fromC_at6 = try db.saveMessage(.stub(
+      from: contactC,
+      to: groupC,
+      at: 6,
+      isUnread: true
+    ))
+
+    // Fetch group chats excluding messages from blocked contacts:
+
+    XCTAssertNoDifference(try db.fetchGroupChatInfos(.init(excludeBlockedContacts: true)), [
+      GroupChatInfo(
+        group: groupA,
+        lastMessage: groupA_message_fromB_at2,
+        unreadCount: 2
+      ),
+    ])
+
+    // Fetch group chats including messages from blocked contacts:
+
+    XCTAssertNoDifference(try db.fetchGroupChatInfos(.init(excludeBlockedContacts: false)), [
+      GroupChatInfo(
+        group: groupC,
+        lastMessage: groupC_message_fromC_at6,
+        unreadCount: 2
+      ),
+      GroupChatInfo(
+        group: groupB,
+        lastMessage: groupB_message_fromC_at4,
+        unreadCount: 1
+      ),
+      GroupChatInfo(
+        group: groupA,
+        lastMessage: groupA_message_fromC_at3,
+        unreadCount: 3
+      ),
+    ])
+  }
+
+  func testExcludeMessagesFromBannedContacts() throws {
+    // Mock up contacts:
+
+    let contactA = try db.saveContact(.stub("A"))
+    let contactB = try db.saveContact(.stub("B"))
+    let contactC = try db.saveContact(.stub("C").withBanned(true))
+
+    // Mock up groups:
+
+    let groupA = try db.saveGroup(.stub(
+      "A",
+      leaderId: contactA.id,
+      createdAt: .stub(1)
+    ))
+
+    try db.saveGroupMember(GroupMember(groupId: groupA.id, contactId: contactA.id))
+    try db.saveGroupMember(GroupMember(groupId: groupA.id, contactId: contactB.id))
+    try db.saveGroupMember(GroupMember(groupId: groupA.id, contactId: contactC.id))
+
+    let groupB = try db.saveGroup(.stub(
+      "B",
+      leaderId: contactB.id,
+      createdAt: .stub(2)
+    ))
+
+    try db.saveGroupMember(GroupMember(groupId: groupB.id, contactId: contactA.id))
+    try db.saveGroupMember(GroupMember(groupId: groupB.id, contactId: contactB.id))
+    try db.saveGroupMember(GroupMember(groupId: groupB.id, contactId: contactC.id))
+
+    let groupC = try db.saveGroup(.stub(
+      "C",
+      leaderId: contactC.id,
+      createdAt: .stub(3)
+    ))
+
+    try db.saveGroupMember(GroupMember(groupId: groupC.id, contactId: contactA.id))
+    try db.saveGroupMember(GroupMember(groupId: groupC.id, contactId: contactB.id))
+    try db.saveGroupMember(GroupMember(groupId: groupC.id, contactId: contactC.id))
+
+    // Mock up messages in group A:
+
+    try db.saveMessage(.stub(
+      from: contactA,
+      to: groupA,
+      at: 1,
+      isUnread: true
+    ))
+
+    let groupA_message_fromB_at2 = try db.saveMessage(.stub(
+      from: contactB,
+      to: groupA,
+      at: 2,
+      isUnread: true
+    ))
+
+    let groupA_message_fromC_at3 = try db.saveMessage(.stub(
+      from: contactC,
+      to: groupA,
+      at: 3,
+      isUnread: true
+    ))
+
+    // Mock up messages in group B:
+
+    let groupB_message_fromC_at4 = try db.saveMessage(.stub(
+      from: contactC,
+      to: groupB,
+      at: 4,
+      isUnread: true
+    ))
+
+    // Mock up messages in group C:
+
+    try db.saveMessage(.stub(
+      from: contactA,
+      to: groupC,
+      at: 5,
+      isUnread: true
+    ))
+
+    let groupC_message_fromC_at6 = try db.saveMessage(.stub(
+      from: contactC,
+      to: groupC,
+      at: 6,
+      isUnread: true
+    ))
+
+    // Fetch group chats excluding messages from banned contacts:
+
+    XCTAssertNoDifference(try db.fetchGroupChatInfos(.init(excludeBannedContacts: true)), [
+      GroupChatInfo(
+        group: groupA,
+        lastMessage: groupA_message_fromB_at2,
+        unreadCount: 2
+      ),
+    ])
+
+    // Fetch group chats including messages from banned contacts:
+
+    XCTAssertNoDifference(try db.fetchGroupChatInfos(.init(excludeBannedContacts: false)), [
+      GroupChatInfo(
+        group: groupC,
+        lastMessage: groupC_message_fromC_at6,
+        unreadCount: 2
+      ),
+      GroupChatInfo(
+        group: groupB,
+        lastMessage: groupB_message_fromC_at4,
+        unreadCount: 1
+      ),
+      GroupChatInfo(
+        group: groupA,
+        lastMessage: groupA_message_fromC_at3,
+        unreadCount: 3
+      ),
+    ])
+  }
 }