diff --git a/keyserver/src/creators/message-creator.js b/keyserver/src/creators/message-creator.js
--- a/keyserver/src/creators/message-creator.js
+++ b/keyserver/src/creators/message-creator.js
@@ -620,6 +620,10 @@
   const lastMessageExpression = SQL`
     last_message = GREATEST(last_message, CASE 
   `;
+  const lastMessageForUnreadCheckExpression = SQL`
+    , last_message_for_unread_check =
+      GREATEST(last_message_for_unread_check, CASE 
+  `;
   const lastReadMessageExpression = SQL`
     , last_read_message = GREATEST(last_read_message, CASE 
   `;
@@ -633,6 +637,9 @@
     lastMessageExpression.append(SQL`
       WHEN user = ${userID} AND thread = ${threadID} THEN ${latestMessage}
     `);
+    lastMessageForUnreadCheckExpression.append(SQL`
+      WHEN user = ${userID} AND thread = ${threadID} THEN ${latestMessage}
+    `);
     if (latestReadMessage) {
       shouldUpdateLastReadMessage = true;
       lastReadMessageExpression.append(SQL`
@@ -644,6 +651,10 @@
     ELSE last_message
     END)
   `);
+  lastMessageForUnreadCheckExpression.append(SQL`
+    ELSE last_message_for_unread_check
+    END)
+  `);
   lastReadMessageExpression.append(SQL`
     ELSE last_read_message
     END)
@@ -654,6 +665,7 @@
   );
 
   query.append(lastMessageExpression);
+  query.append(lastMessageForUnreadCheckExpression);
   if (shouldUpdateLastReadMessage) {
     query.append(lastReadMessageExpression);
   }
diff --git a/keyserver/src/updaters/activity-updaters.js b/keyserver/src/updaters/activity-updaters.js
--- a/keyserver/src/updaters/activity-updaters.js
+++ b/keyserver/src/updaters/activity-updaters.js
@@ -495,7 +495,7 @@
   threadIDs: $ReadOnlyArray<string>,
 ) {
   const query = SQL`
-    SELECT thread, last_message, last_read_message
+    SELECT thread, last_message_for_unread_check, last_read_message
     FROM memberships
     WHERE user = ${viewer.userID} AND thread IN (${threadIDs})
   `;
@@ -504,7 +504,7 @@
   const lastMessages = new Map<string, LastMessageInfo>();
   for (const row of result) {
     const threadID = row.thread.toString();
-    const lastMessage = row.last_message;
+    const lastMessage = row.last_message_for_unread_check;
     const lastReadMessage = row.last_read_message;
     lastMessages.set(threadID, { lastMessage, lastReadMessage });
   }
diff --git a/keyserver/src/updaters/thread-permission-updaters.js b/keyserver/src/updaters/thread-permission-updaters.js
--- a/keyserver/src/updaters/thread-permission-updaters.js
+++ b/keyserver/src/updaters/thread-permission-updaters.js
@@ -958,7 +958,6 @@
         ? JSON.stringify(rowToSave.permissionsForChildren)
         : null,
       rowToSave.unread ? 1 : 0,
-      0,
     ]);
   }
 
@@ -974,7 +973,7 @@
     const batch = insertRows.splice(0, membershipInsertBatchSize);
     const query = SQL`
       INSERT INTO memberships (user, thread, role, creation_time, subscription,
-        permissions, permissions_for_children, last_message, last_read_message)
+        permissions, permissions_for_children, last_message_for_unread_check)
       VALUES ${batch}
       ON DUPLICATE KEY UPDATE
         subscription = IF(
@@ -1007,34 +1006,12 @@
     thread,
   ]);
 
-  const unreadUserThreadPairs = joinRows
-    .filter(([, , unread]) => !!unread)
-    .map(([user, thread]) => [user, thread]);
-
-  let lastReadMessageExpression;
-  if (unreadUserThreadPairs.length === 0) {
-    lastReadMessageExpression = SQL`
-      GREATEST(COALESCE(all_users_query.message, 0), 
-        COALESCE(last_subthread_message_for_user_query.message, 0))
-    `;
-  } else {
-    lastReadMessageExpression = SQL`
-      (CASE 
-        WHEN ((mm.user, mm.thread) in (${unreadUserThreadPairs})) THEN 0
-        ELSE GREATEST(COALESCE(all_users_query.message, 0), 
-          COALESCE(last_subthread_message_for_user_query.message, 0))
-      END)
-    `;
-  }
-
   // We join two subqueries with the memberships table:
   // - the first subquery calculates the oldest non-CREATE_SUB_THREAD
   //   message, which is the same for all users
   // - the second subquery calculates the oldest CREATE_SUB_THREAD messages,
   //   which can be different for each user because of visibility permissions
   // Then we set the `last_message` column to the greater value of the two.
-  // For `last_read_message` we do the same but only if the user should have
-  // the "unread" status set for this thread.
   const query = SQL`
     UPDATE memberships mm
     LEFT JOIN (
@@ -1053,13 +1030,12 @@
     ) last_subthread_message_for_user_query 
     ON mm.thread = last_subthread_message_for_user_query.thread 
       AND mm.user = last_subthread_message_for_user_query.user
-    SET
-      mm.last_message = GREATEST(COALESCE(all_users_query.message, 0), 
-        COALESCE(last_subthread_message_for_user_query.message, 0)),
-      mm.last_read_message =
+    SET mm.last_message = GREATEST(
+      COALESCE(all_users_query.message, 0),
+      COALESCE(last_subthread_message_for_user_query.message, 0)
+    )
+    WHERE (mm.user, mm.thread) IN (${joinedUserThreadPairs})
   `;
-  query.append(lastReadMessageExpression);
-  query.append(SQL`WHERE (mm.user, mm.thread) IN (${joinedUserThreadPairs});`);
 
   await dbQuery(query);
 }
@@ -1082,13 +1058,15 @@
     null,
     0,
     0,
+    0,
   ]);
 
   while (insertRows.length > 0) {
     const batch = insertRows.splice(0, membershipInsertBatchSize);
     const query = SQL`
       INSERT INTO memberships (user, thread, role, creation_time, subscription,
-        permissions, permissions_for_children, last_message, last_read_message)
+        permissions, permissions_for_children, last_message, last_read_message,
+        last_message_for_unread_check)
       VALUES ${batch}
       ON DUPLICATE KEY UPDATE
         role = -1,
@@ -1096,7 +1074,8 @@
         permissions_for_children = NULL,
         subscription = ${defaultSubscriptionString},
         last_message = 0,
-        last_read_message = 0
+        last_read_message = 0,
+        last_message_for_unread_check = 0
     `;
     await dbQuery(query);
   }