diff --git a/changelog.d/18157.bugfix b/changelog.d/18157.bugfix
new file mode 100644
index 0000000000000000000000000000000000000000..307e9c96ffa81de156fe2e9ff056cb81ab823bcd
--- /dev/null
+++ b/changelog.d/18157.bugfix
@@ -0,0 +1 @@
+Prevent suspended users from sending encrypted messages.
diff --git a/synapse/handlers/message.py b/synapse/handlers/message.py
index df3010ecf689c14e2c57e7b4c64e69ab688b3eac..4642b8b57861f3949879a1c5ea161264a30ad144 100644
--- a/synapse/handlers/message.py
+++ b/synapse/handlers/message.py
@@ -644,11 +644,33 @@ class EventCreationHandler:
         """
         await self.auth_blocking.check_auth_blocking(requester=requester)
 
-        if event_dict["type"] == EventTypes.Message:
-            requester_suspended = await self.store.get_user_suspended_status(
-                requester.user.to_string()
-            )
-            if requester_suspended:
+        requester_suspended = await self.store.get_user_suspended_status(
+            requester.user.to_string()
+        )
+        if requester_suspended:
+            # We want to allow suspended users to perform "corrective" actions
+            # asked of them by server admins, such as redact their messages and
+            # leave rooms.
+            if event_dict["type"] in ["m.room.redaction", "m.room.member"]:
+                if event_dict["type"] == "m.room.redaction":
+                    event = await self.store.get_event(
+                        event_dict["content"]["redacts"], allow_none=True
+                    )
+                    if event:
+                        if event.sender != requester.user.to_string():
+                            raise SynapseError(
+                                403,
+                                "You can only redact your own events while account is suspended.",
+                                Codes.USER_ACCOUNT_SUSPENDED,
+                            )
+                if event_dict["type"] == "m.room.member":
+                    if event_dict["content"]["membership"] != "leave":
+                        raise SynapseError(
+                            403,
+                            "Changing membership while account is suspended is not allowed.",
+                            Codes.USER_ACCOUNT_SUSPENDED,
+                        )
+            else:
                 raise SynapseError(
                     403,
                     "Sending messages while account is suspended is not allowed.",
diff --git a/tests/rest/client/test_rooms.py b/tests/rest/client/test_rooms.py
index 604b58515038eeda781ece55eb74b13850f72ca0..f6ec8a8b7b9192ff21850c6df46b4bc06ea8850a 100644
--- a/tests/rest/client/test_rooms.py
+++ b/tests/rest/client/test_rooms.py
@@ -1371,6 +1371,23 @@ class RoomJoinTestCase(RoomBase):
         )
         self.assertEqual(channel.json_body["errcode"], "M_USER_SUSPENDED")
 
+    def test_suspended_user_can_leave_room(self) -> None:
+        channel = self.make_request(
+            "POST", f"/join/{self.room1}", access_token=self.tok1
+        )
+        self.assertEqual(channel.code, 200)
+
+        # set the user as suspended
+        self.get_success(self.store.set_user_suspended_status(self.user1, True))
+
+        # leave room
+        channel = self.make_request(
+            "POST",
+            f"/rooms/{self.room1}/leave",
+            access_token=self.tok1,
+        )
+        self.assertEqual(channel.code, 200)
+
 
 class RoomAppserviceTsParamTestCase(unittest.HomeserverTestCase):
     servlets = [
@@ -3989,10 +4006,25 @@ class UserSuspensionTests(unittest.HomeserverTestCase):
         self.user2 = self.register_user("teresa", "hackme")
         self.tok2 = self.login("teresa", "hackme")
 
-        self.room1 = self.helper.create_room_as(room_creator=self.user1, tok=self.tok1)
+        self.admin = self.register_user("admin", "pass", True)
+        self.admin_tok = self.login("admin", "pass")
+
+        self.room1 = self.helper.create_room_as(
+            room_creator=self.user1, tok=self.tok1, room_version="11"
+        )
         self.store = hs.get_datastores().main
 
-    def test_suspended_user_cannot_send_message_to_room(self) -> None:
+        self.room2 = self.helper.create_room_as(
+            room_creator=self.user1, is_public=False, tok=self.tok1
+        )
+        self.helper.send_state(
+            self.room2,
+            EventTypes.RoomEncryption,
+            {EventContentFields.ENCRYPTION_ALGORITHM: "m.megolm.v1.aes-sha2"},
+            tok=self.tok1,
+        )
+
+    def test_suspended_user_cannot_send_message_to_public_room(self) -> None:
         # set the user as suspended
         self.get_success(self.store.set_user_suspended_status(self.user1, True))
 
@@ -4004,6 +4036,24 @@ class UserSuspensionTests(unittest.HomeserverTestCase):
         )
         self.assertEqual(channel.json_body["errcode"], "M_USER_SUSPENDED")
 
+    def test_suspended_user_cannot_send_message_to_encrypted_room(self) -> None:
+        channel = self.make_request(
+            "PUT",
+            f"/_synapse/admin/v1/suspend/{self.user1}",
+            {"suspend": True},
+            access_token=self.admin_tok,
+        )
+        self.assertEqual(channel.code, 200)
+        self.assertEqual(channel.json_body, {f"user_{self.user1}_suspended": True})
+
+        channel = self.make_request(
+            "PUT",
+            f"/rooms/{self.room2}/send/m.room.encrypted/1",
+            access_token=self.tok1,
+            content={},
+        )
+        self.assertEqual(channel.json_body["errcode"], "M_USER_SUSPENDED")
+
     def test_suspended_user_cannot_change_profile_data(self) -> None:
         # set the user as suspended
         self.get_success(self.store.set_user_suspended_status(self.user1, True))
@@ -4069,3 +4119,51 @@ class UserSuspensionTests(unittest.HomeserverTestCase):
             shorthand=False,
         )
         self.assertEqual(channel.code, 200)
+
+        channel = self.make_request(
+            "PUT",
+            f"/_matrix/client/v3/rooms/{self.room1}/send/m.room.redaction/3456346",
+            access_token=self.tok1,
+            content={"reason": "bogus", "redacts": event_id},
+            shorthand=False,
+        )
+        self.assertEqual(channel.json_body["errcode"], "M_USER_SUSPENDED")
+
+        channel = self.make_request(
+            "PUT",
+            f"/_matrix/client/v3/rooms/{self.room1}/send/m.room.redaction/3456346",
+            access_token=self.tok1,
+            content={"reason": "bogus", "redacts": event_id2},
+            shorthand=False,
+        )
+        self.assertEqual(channel.code, 200)
+
+    def test_suspended_user_cannot_ban_others(self) -> None:
+        # user to ban joins room user1 created
+        self.make_request("POST", f"/rooms/{self.room1}/join", access_token=self.tok2)
+
+        # suspend user1
+        self.get_success(self.store.set_user_suspended_status(self.user1, True))
+
+        # user1 tries to ban other user while suspended
+        channel = self.make_request(
+            "POST",
+            f"/_matrix/client/v3/rooms/{self.room1}/ban",
+            access_token=self.tok1,
+            content={"reason": "spite", "user_id": self.user2},
+            shorthand=False,
+        )
+        self.assertEqual(channel.json_body["errcode"], "M_USER_SUSPENDED")
+
+        # un-suspend user1
+        self.get_success(self.store.set_user_suspended_status(self.user1, False))
+
+        # ban now goes through
+        channel = self.make_request(
+            "POST",
+            f"/_matrix/client/v3/rooms/{self.room1}/ban",
+            access_token=self.tok1,
+            content={"reason": "spite", "user_id": self.user2},
+            shorthand=False,
+        )
+        self.assertEqual(channel.code, 200)