diff --git a/Sources/XXDatabase/Models/ContactChatInfo+GRDB.swift b/Sources/XXDatabase/Models/ContactChatInfo+GRDB.swift
index 47315f4fcb4652ee8ab55eb4f6000eec6534ab70..6f50587b1bd3e7b9301d26a7c0782fff2f38ee8a 100644
--- a/Sources/XXDatabase/Models/ContactChatInfo+GRDB.swift
+++ b/Sources/XXDatabase/Models/ContactChatInfo+GRDB.swift
@@ -17,6 +17,16 @@ extension ContactChatInfo: FetchableRecord {
       _ = sqlArguments.append(contentsOf: sqlArgumentsAuthStatus(authStatus))
     }
 
+    if let isBlocked = query.isBlocked {
+      sqlWhere.append("AND c2.isBlocked = :isBlocked")
+      _ = sqlArguments.append(contentsOf: StatementArguments(["isBlocked": isBlocked]))
+    }
+
+    if let isBanned = query.isBanned {
+      sqlWhere.append("AND c2.isBanned = :isBanned")
+      _ = sqlArguments.append(contentsOf: StatementArguments(["isBanned": isBanned]))
+    }
+
     let sql = """
       SELECT
         -- All contact columns:
diff --git a/Sources/XXModels/Models/ContactChatInfo.swift b/Sources/XXModels/Models/ContactChatInfo.swift
index b7eb7134a036cf2ff4c269a441b144a83106aa50..37f2f505c5089928d5da827c703e0ede2aba965a 100644
--- a/Sources/XXModels/Models/ContactChatInfo.swift
+++ b/Sources/XXModels/Models/ContactChatInfo.swift
@@ -51,12 +51,24 @@ extension ContactChatInfo {
     ///     If set, only chats with contacts that have any of the provided
     ///     auth statuses will be included.
     ///     If `nil` (default), the filter is not used.
+    ///   - isBlocked: Filter by other contact's `isBlocked` status.
+    ///     If `true`, only chats with blocked contacts are included.
+    ///     If `false`, only chats with non-blocked contacts are included.
+    ///     If `nil` (default), the filter is not used.
+    ///   - isBanned: Filter by other contact's `isBanned` status
+    ///     If `true`, only chats with banned contacts are included.
+    ///     If `false`, only chats with non-banned contacts are included.
+    ///     If `nil` (default), the filter is not used.
     public init(
       userId: Contact.ID,
-      authStatus: Set<Contact.AuthStatus>? = nil
+      authStatus: Set<Contact.AuthStatus>? = nil,
+      isBlocked: Bool? = nil,
+      isBanned: Bool? = nil
     ) {
       self.userId = userId
       self.authStatus = authStatus
+      self.isBlocked = isBlocked
+      self.isBanned = isBanned
     }
 
     /// Current user's contact ID
@@ -68,5 +80,19 @@ extension ContactChatInfo {
     /// auth statuses will be included.
     /// If `nil`, the filter is not used.
     public var authStatus: Set<Contact.AuthStatus>?
+
+    /// Filter by other contact's `isBlocked` status
+    ///
+    /// If `true`, only chats with blocked contacts are included.
+    /// If `false`, only chats with non-blocked contacts are included.
+    /// If `nil`, the filter is not used.
+    public var isBlocked: Bool?
+
+    /// Filter by other contact's `isBanned` status
+    ///
+    /// If `true`, only chats with banned contacts are included.
+    /// If `false`, only chats with non-banned contacts are included.
+    /// If `nil`, the filter is not used.
+    public var isBanned: Bool?
   }
 }
diff --git a/Tests/XXDatabaseTests/ContactChatInfo+GRDBTests.swift b/Tests/XXDatabaseTests/ContactChatInfo+GRDBTests.swift
index 05a1cb0c2294efe6e0a906f7e41786f4eac75940..b142b68e0e4e833598f1da2fcb18e40b1adc1cda 100644
--- a/Tests/XXDatabaseTests/ContactChatInfo+GRDBTests.swift
+++ b/Tests/XXDatabaseTests/ContactChatInfo+GRDBTests.swift
@@ -259,4 +259,258 @@ final class ContactChatInfoGRDBTests: XCTestCase {
       ]
     )
   }
+
+  func testFetchingByContactBlockedStatus() throws {
+    // Mock up contacts:
+
+    let contactA = try db.saveContact(.stub("A").withBlocked(false))
+    let contactB = try db.saveContact(.stub("B").withBlocked(true))
+    let contactC = try db.saveContact(.stub("C").withBlocked(false))
+    let contactD = try db.saveContact(.stub("D").withBlocked(true))
+
+    // Mock up conversation between contact A and B:
+
+    try db.saveMessage(.stub(
+      from: contactA,
+      to: contactB,
+      at: 1,
+      isUnread: false
+    ))
+
+    try db.saveMessage(.stub(
+      from: contactB,
+      to: contactA,
+      at: 2,
+      isUnread: true
+    ))
+
+    let lastMessage_betweenAandB_at3 = try db.saveMessage(.stub(
+      from: contactA,
+      to: contactB,
+      at: 3,
+      isUnread: true
+    ))
+
+    // Mock up conversation between contact A and C:
+
+    try db.saveMessage(.stub(
+      from: contactA,
+      to: contactC,
+      at: 4,
+      isUnread: false
+    ))
+
+    let lastMessage_betweenAandC_at5 = try db.saveMessage(.stub(
+      from: contactC,
+      to: contactA,
+      at: 5,
+      isUnread: true
+    ))
+
+    // Mock up conversation between contact A and D:
+
+    try db.saveMessage(.stub(
+      from: contactA,
+      to: contactD,
+      at: 6,
+      isUnread: false
+    ))
+
+    let lastMessage_betweenAandD_at7 = try db.saveMessage(.stub(
+      from: contactD,
+      to: contactA,
+      at: 7,
+      isUnread: false
+    ))
+
+    // Fetch chats between contact A and blocked contacts:
+
+    XCTAssertNoDifference(
+      try db.fetchContactChatInfos(ContactChatInfo.Query(
+        userId: contactA.id,
+        isBlocked: true
+      )),
+      [
+        ContactChatInfo(
+          contact: contactD,
+          lastMessage: lastMessage_betweenAandD_at7,
+          unreadCount: 0
+        ),
+        ContactChatInfo(
+          contact: contactB,
+          lastMessage: lastMessage_betweenAandB_at3,
+          unreadCount: 2
+        ),
+      ]
+    )
+
+    // Fetch chats between contact A and non-blocked contacts:
+
+    XCTAssertNoDifference(
+      try db.fetchContactChatInfos(ContactChatInfo.Query(
+        userId: contactA.id,
+        isBlocked: false
+      )),
+      [
+        ContactChatInfo(
+          contact: contactC,
+          lastMessage: lastMessage_betweenAandC_at5,
+          unreadCount: 1
+        ),
+      ]
+    )
+
+    // Fetch chats between contact A and other contacts, regardless its `isBlocked` status:
+
+    XCTAssertNoDifference(
+      try db.fetchContactChatInfos(ContactChatInfo.Query(
+        userId: contactA.id,
+        isBlocked: nil
+      )),
+      [
+        ContactChatInfo(
+          contact: contactD,
+          lastMessage: lastMessage_betweenAandD_at7,
+          unreadCount: 0
+        ),
+        ContactChatInfo(
+          contact: contactC,
+          lastMessage: lastMessage_betweenAandC_at5,
+          unreadCount: 1
+        ),
+        ContactChatInfo(
+          contact: contactB,
+          lastMessage: lastMessage_betweenAandB_at3,
+          unreadCount: 2
+        ),
+      ]
+    )
+  }
+
+  func testFetchingByContactBannedStatus() throws {
+    // Mock up contacts:
+
+    let contactA = try db.saveContact(.stub("A").withBanned(false))
+    let contactB = try db.saveContact(.stub("B").withBanned(true))
+    let contactC = try db.saveContact(.stub("C").withBanned(false))
+    let contactD = try db.saveContact(.stub("D").withBanned(true))
+
+    // Mock up conversation between contact A and B:
+
+    try db.saveMessage(.stub(
+      from: contactA,
+      to: contactB,
+      at: 1,
+      isUnread: false
+    ))
+
+    try db.saveMessage(.stub(
+      from: contactB,
+      to: contactA,
+      at: 2,
+      isUnread: true
+    ))
+
+    let lastMessage_betweenAandB_at3 = try db.saveMessage(.stub(
+      from: contactA,
+      to: contactB,
+      at: 3,
+      isUnread: true
+    ))
+
+    // Mock up conversation between contact A and C:
+
+    try db.saveMessage(.stub(
+      from: contactA,
+      to: contactC,
+      at: 4,
+      isUnread: false
+    ))
+
+    let lastMessage_betweenAandC_at5 = try db.saveMessage(.stub(
+      from: contactC,
+      to: contactA,
+      at: 5,
+      isUnread: true
+    ))
+
+    // Mock up conversation between contact A and D:
+
+    try db.saveMessage(.stub(
+      from: contactA,
+      to: contactD,
+      at: 6,
+      isUnread: false
+    ))
+
+    let lastMessage_betweenAandD_at7 = try db.saveMessage(.stub(
+      from: contactD,
+      to: contactA,
+      at: 7,
+      isUnread: false
+    ))
+
+    // Fetch chats between contact A and banned contacts:
+
+    XCTAssertNoDifference(
+      try db.fetchContactChatInfos(ContactChatInfo.Query(
+        userId: contactA.id,
+        isBanned: true
+      )),
+      [
+        ContactChatInfo(
+          contact: contactD,
+          lastMessage: lastMessage_betweenAandD_at7,
+          unreadCount: 0
+        ),
+        ContactChatInfo(
+          contact: contactB,
+          lastMessage: lastMessage_betweenAandB_at3,
+          unreadCount: 2
+        ),
+      ]
+    )
+
+    // Fetch chats between contact A and non-banned contacts:
+
+    XCTAssertNoDifference(
+      try db.fetchContactChatInfos(ContactChatInfo.Query(
+        userId: contactA.id,
+        isBanned: false
+      )),
+      [
+        ContactChatInfo(
+          contact: contactC,
+          lastMessage: lastMessage_betweenAandC_at5,
+          unreadCount: 1
+        ),
+      ]
+    )
+
+    // Fetch chats between contact A and other contacts, regardless its `isBanned` status:
+
+    XCTAssertNoDifference(
+      try db.fetchContactChatInfos(ContactChatInfo.Query(
+        userId: contactA.id,
+        isBanned: nil
+      )),
+      [
+        ContactChatInfo(
+          contact: contactD,
+          lastMessage: lastMessage_betweenAandD_at7,
+          unreadCount: 0
+        ),
+        ContactChatInfo(
+          contact: contactC,
+          lastMessage: lastMessage_betweenAandC_at5,
+          unreadCount: 1
+        ),
+        ContactChatInfo(
+          contact: contactB,
+          lastMessage: lastMessage_betweenAandB_at3,
+          unreadCount: 2
+        ),
+      ]
+    )
+  }
 }