diff --git a/changelog.d/7716.feature b/changelog.d/7716.feature
new file mode 100644
index 0000000000000000000000000000000000000000..ecc3ffd8d5fc60cf4b2a4f65d636b8f4e5b3dc0e
--- /dev/null
+++ b/changelog.d/7716.feature
@@ -0,0 +1 @@
+Add a per-room counter for unread messages in responses to `/sync` requests. Implements [MSC2625](https://github.com/matrix-org/matrix-doc/pull/2625).
diff --git a/synapse/push/push_tools.py b/synapse/push/push_tools.py
index 9f264ca4a4334974372f66e603edcaaaf77d1667..4ea683fee0106578a112fdf1cb3eb7e7b83c5fc9 100644
--- a/synapse/push/push_tools.py
+++ b/synapse/push/push_tools.py
@@ -42,7 +42,7 @@ def get_badge_count(store, user_id):
             # We're populating this badge using the unread_count (instead of the
             # notify_count) as this badge is the number of missed messages, not the
             # number of missed notifications.
-            badge += 1 if notifs["unread_count"] else 0
+            badge += 1 if notifs.get("unread_count") else 0
     return badge
 
 
diff --git a/synapse/storage/data_stores/main/event_push_actions.py b/synapse/storage/data_stores/main/event_push_actions.py
index ba1b33a0a9f927c0c8c30757a72b2aa5d735763c..815d52ab4cfbfd684da00d134873416dd42ff4d1 100644
--- a/synapse/storage/data_stores/main/event_push_actions.py
+++ b/synapse/storage/data_stores/main/event_push_actions.py
@@ -123,7 +123,7 @@ class EventPushActionsWorkerStore(SQLBaseStore):
         txn.execute(sql, (room_id, last_read_event_id))
         results = txn.fetchall()
         if len(results) == 0:
-            return {"notify_count": 0, "highlight_count": 0}
+            return {"notify_count": 0, "highlight_count": 0, "unread_count": 0}
 
         stream_ordering = results[0][0]