diff --git a/Sources/XXDatabase/Models/GroupChatInfo+GRDB.swift b/Sources/XXDatabase/Models/GroupChatInfo+GRDB.swift
index 20062ab25781e6b59a9d4cb8b4d1ab3480d72ee9..a44b98df23f271de5c26009ac75c0a7da2d9a1b2 100644
--- a/Sources/XXDatabase/Models/GroupChatInfo+GRDB.swift
+++ b/Sources/XXDatabase/Models/GroupChatInfo+GRDB.swift
@@ -18,17 +18,32 @@ extension GroupChatInfo: FetchableRecord {
       _ = sqlArguments.append(contentsOf: sqlArgumentsAuthStatus(authStatus))
     }
 
-    if query.excludeBlockedContacts || query.excludeBannedContacts {
+    if query.isLeaderBlocked != nil || query.isLeaderBanned != nil {
       sqlJoins.append("INNER JOIN contacts l ON g.leaderId = l.id")
+
+      if let isLeaderBlocked = query.isLeaderBlocked {
+        sqlWhere.append("l.isBlocked = :isLeaderBlocked")
+        _ = sqlArguments.append(contentsOf: StatementArguments([
+          "isLeaderBlocked": isLeaderBlocked
+        ]))
+      }
+
+      if let isLeaderBanned = query.isLeaderBanned {
+        sqlWhere.append("l.isBanned = :isLeaderBanned")
+        _ = sqlArguments.append(contentsOf: StatementArguments([
+          "isLeaderBanned": isLeaderBanned
+        ]))
+      }
+    }
+
+    if query.excludeBlockedContactsMessages || query.excludeBannedContactsMessages {
       sqlJoins.append("INNER JOIN contacts s ON m.senderId = s.id")
 
-      if query.excludeBlockedContacts {
-        sqlWhere.append("l.isBlocked != 1")
+      if query.excludeBlockedContactsMessages {
         sqlWhere.append("s.isBlocked != 1")
       }
 
-      if query.excludeBannedContacts {
-        sqlWhere.append("l.isBanned != 1")
+      if query.excludeBannedContactsMessages {
         sqlWhere.append("s.isBanned != 1")
       }
     }
diff --git a/Sources/XXModels/Models/GroupChatInfo.swift b/Sources/XXModels/Models/GroupChatInfo.swift
index 8e92eddeeb155550a8659bbd7c3ab0b7f3f01206..4e5f4c592f4176072817198ad4f4afefa16b5aeb 100644
--- a/Sources/XXModels/Models/GroupChatInfo.swift
+++ b/Sources/XXModels/Models/GroupChatInfo.swift
@@ -49,18 +49,30 @@ 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`).
+    ///   - isLeaderBlocked: Filter by leader contact's `isBlocked` status.
+    ///     If `true`, only groups with blocked leader contacts are included.
+    ///     If `false`, only groups with non-blocked contacts are included.
+    ///     If `nil` (default), the filter is not used.
+    ///   - isLeaderBanned: Filter by leader contact's `isBlocked` status.
+    ///     If `true`, only groups with blocked leader contacts are included.
+    ///     If `false`, only groups with non-blocked contacts are included.
+    ///     If `nil` (default), the filter is not used.
+    ///   - excludeBlockedContactsMessages: Exclude messages from blocked contacts
+    ///     (defaults to `false`).
+    ///   - excludeBannedContactsMessages: Exclude messages from banned contacts
+    ///     (defaults to `false`).
     public init(
       authStatus: Set<Group.AuthStatus>? = nil,
-      excludeBlockedContacts: Bool = false,
-      excludeBannedContacts: Bool = false
+      isLeaderBlocked: Bool? = nil,
+      isLeaderBanned: Bool? = nil,
+      excludeBlockedContactsMessages: Bool = false,
+      excludeBannedContactsMessages: Bool = false
     ) {
       self.authStatus = authStatus
-      self.excludeBlockedContacts = excludeBlockedContacts
-      self.excludeBannedContacts = excludeBannedContacts
+      self.isLeaderBlocked = isLeaderBlocked
+      self.isLeaderBanned = isLeaderBanned
+      self.excludeBlockedContactsMessages = excludeBlockedContactsMessages
+      self.excludeBannedContactsMessages = excludeBannedContactsMessages
     }
 
     /// Filter groups by auth status
@@ -69,10 +81,24 @@ extension GroupChatInfo {
     /// 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
+    /// Filter by leader contact's `isBlocked` status
+    ///
+    /// If `true`, only groups with blocked leader contacts are included.
+    /// If `false`, only groups with non-blocked contacts are included.
+    /// If `nil`, the filter is not used.
+    public var isLeaderBlocked: Bool?
+
+    /// Filter by leader contact's `isBanned` status
+    ///
+    /// If `true`, only groups with banned leader contacts are included.
+    /// If `false`, only groups with non-banned leader contacts are included.
+    /// If `nil`, the filter is not used.
+    public var isLeaderBanned: Bool?
+
+    /// Exclude messages from blocked contacts.
+    public var excludeBlockedContactsMessages: Bool
 
-    /// Exclude groups with banned leaders and last messages from banned contacts.
-    public var excludeBannedContacts: Bool
+    /// Exclude messages from banned contacts.
+    public var excludeBannedContactsMessages: Bool
   }
 }
diff --git a/Tests/XXDatabaseTests/GroupChatInfo+GRDBTests.swift b/Tests/XXDatabaseTests/GroupChatInfo+GRDBTests.swift
index fd67cc0c6ae9d01815f7ab8fe8a48f6269884c59..8618df81c6a9294548e754a1987f76c84dae876b 100644
--- a/Tests/XXDatabaseTests/GroupChatInfo+GRDBTests.swift
+++ b/Tests/XXDatabaseTests/GroupChatInfo+GRDBTests.swift
@@ -213,7 +213,7 @@ final class GroupChatInfoGRDBTests: XCTestCase {
 
     // Mock up messages in group C:
 
-    try db.saveMessage(.stub(
+    let groupC_message_fromA_at5 = try db.saveMessage(.stub(
       from: contactA,
       to: groupC,
       at: 5,
@@ -229,7 +229,12 @@ final class GroupChatInfoGRDBTests: XCTestCase {
 
     // Fetch group chats excluding messages from blocked contacts:
 
-    XCTAssertNoDifference(try db.fetchGroupChatInfos(.init(excludeBlockedContacts: true)), [
+    XCTAssertNoDifference(try db.fetchGroupChatInfos(.init(excludeBlockedContactsMessages: true)), [
+      GroupChatInfo(
+        group: groupC,
+        lastMessage: groupC_message_fromA_at5,
+        unreadCount: 1
+      ),
       GroupChatInfo(
         group: groupA,
         lastMessage: groupA_message_fromB_at2,
@@ -239,7 +244,7 @@ final class GroupChatInfoGRDBTests: XCTestCase {
 
     // Fetch group chats including messages from blocked contacts:
 
-    XCTAssertNoDifference(try db.fetchGroupChatInfos(.init(excludeBlockedContacts: false)), [
+    XCTAssertNoDifference(try db.fetchGroupChatInfos(.init(excludeBlockedContactsMessages: false)), [
       GroupChatInfo(
         group: groupC,
         lastMessage: groupC_message_fromC_at6,
@@ -331,7 +336,7 @@ final class GroupChatInfoGRDBTests: XCTestCase {
 
     // Mock up messages in group C:
 
-    try db.saveMessage(.stub(
+    let groupC_message_fromA_at5 = try db.saveMessage(.stub(
       from: contactA,
       to: groupC,
       at: 5,
@@ -347,7 +352,12 @@ final class GroupChatInfoGRDBTests: XCTestCase {
 
     // Fetch group chats excluding messages from banned contacts:
 
-    XCTAssertNoDifference(try db.fetchGroupChatInfos(.init(excludeBannedContacts: true)), [
+    XCTAssertNoDifference(try db.fetchGroupChatInfos(.init(excludeBannedContactsMessages: true)), [
+      GroupChatInfo(
+        group: groupC,
+        lastMessage: groupC_message_fromA_at5,
+        unreadCount: 1
+      ),
       GroupChatInfo(
         group: groupA,
         lastMessage: groupA_message_fromB_at2,
@@ -357,7 +367,7 @@ final class GroupChatInfoGRDBTests: XCTestCase {
 
     // Fetch group chats including messages from banned contacts:
 
-    XCTAssertNoDifference(try db.fetchGroupChatInfos(.init(excludeBannedContacts: false)), [
+    XCTAssertNoDifference(try db.fetchGroupChatInfos(.init(excludeBannedContactsMessages: false)), [
       GroupChatInfo(
         group: groupC,
         lastMessage: groupC_message_fromC_at6,
@@ -375,4 +385,190 @@ final class GroupChatInfoGRDBTests: XCTestCase {
       ),
     ])
   }
+
+  func testFilterGroupsWithBlockedLeaders() 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)
+    ))
+
+    let groupB = try db.saveGroup(.stub(
+      "B",
+      leaderId: contactB.id,
+      createdAt: .stub(2)
+    ))
+
+    let groupC = try db.saveGroup(.stub(
+      "C",
+      leaderId: contactC.id,
+      createdAt: .stub(3)
+    ))
+
+    // Mock up messages:
+
+    let groupA_message_fromA_at1 = try db.saveMessage(.stub(
+      from: contactA,
+      to: groupA,
+      at: 1
+    ))
+
+    let groupB_message_fromA_at2 = try db.saveMessage(.stub(
+      from: contactA,
+      to: groupB,
+      at: 2
+    ))
+
+    let groupC_message_fromA_at3 = try db.saveMessage(.stub(
+      from: contactA,
+      to: groupC,
+      at: 3
+    ))
+
+    // Fetch group chats with blocked leaders:
+
+    XCTAssertNoDifference(try db.fetchGroupChatInfos(.init(isLeaderBlocked: true)), [
+      GroupChatInfo(
+        group: groupC,
+        lastMessage: groupC_message_fromA_at3,
+        unreadCount: 0
+      ),
+    ])
+
+    // Fetch group chats with non-blocked leaders:
+
+    XCTAssertNoDifference(try db.fetchGroupChatInfos(.init(isLeaderBlocked: false)), [
+      GroupChatInfo(
+        group: groupB,
+        lastMessage: groupB_message_fromA_at2,
+        unreadCount: 0
+      ),
+      GroupChatInfo(
+        group: groupA,
+        lastMessage: groupA_message_fromA_at1,
+        unreadCount: 0
+      ),
+    ])
+
+    // Fetch group chats with regardless leader's blocked status:
+
+    XCTAssertNoDifference(try db.fetchGroupChatInfos(.init(isLeaderBlocked: nil)), [
+      GroupChatInfo(
+        group: groupC,
+        lastMessage: groupC_message_fromA_at3,
+        unreadCount: 0
+      ),
+      GroupChatInfo(
+        group: groupB,
+        lastMessage: groupB_message_fromA_at2,
+        unreadCount: 0
+      ),
+      GroupChatInfo(
+        group: groupA,
+        lastMessage: groupA_message_fromA_at1,
+        unreadCount: 0
+      ),
+    ])
+  }
+
+  func testFilterGroupsWithBannedLeaders() 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)
+    ))
+
+    let groupB = try db.saveGroup(.stub(
+      "B",
+      leaderId: contactB.id,
+      createdAt: .stub(2)
+    ))
+
+    let groupC = try db.saveGroup(.stub(
+      "C",
+      leaderId: contactC.id,
+      createdAt: .stub(3)
+    ))
+
+    // Mock up messages:
+
+    let groupA_message_fromA_at1 = try db.saveMessage(.stub(
+      from: contactA,
+      to: groupA,
+      at: 1
+    ))
+
+    let groupB_message_fromA_at2 = try db.saveMessage(.stub(
+      from: contactA,
+      to: groupB,
+      at: 2
+    ))
+
+    let groupC_message_fromA_at3 = try db.saveMessage(.stub(
+      from: contactA,
+      to: groupC,
+      at: 3
+    ))
+
+    // Fetch group chats with banned leaders:
+
+    XCTAssertNoDifference(try db.fetchGroupChatInfos(.init(isLeaderBanned: true)), [
+      GroupChatInfo(
+        group: groupC,
+        lastMessage: groupC_message_fromA_at3,
+        unreadCount: 0
+      ),
+    ])
+
+    // Fetch group chats with non-banned leaders:
+
+    XCTAssertNoDifference(try db.fetchGroupChatInfos(.init(isLeaderBanned: false)), [
+      GroupChatInfo(
+        group: groupB,
+        lastMessage: groupB_message_fromA_at2,
+        unreadCount: 0
+      ),
+      GroupChatInfo(
+        group: groupA,
+        lastMessage: groupA_message_fromA_at1,
+        unreadCount: 0
+      ),
+    ])
+
+    // Fetch group chats with regardless leader's banned status:
+
+    XCTAssertNoDifference(try db.fetchGroupChatInfos(.init(isLeaderBanned: nil)), [
+      GroupChatInfo(
+        group: groupC,
+        lastMessage: groupC_message_fromA_at3,
+        unreadCount: 0
+      ),
+      GroupChatInfo(
+        group: groupB,
+        lastMessage: groupB_message_fromA_at2,
+        unreadCount: 0
+      ),
+      GroupChatInfo(
+        group: groupA,
+        lastMessage: groupA_message_fromA_at1,
+        unreadCount: 0
+      ),
+    ])
+  }
 }