diff --git a/synapse/federation/transport/client.py b/synapse/federation/transport/client.py
index ce68cc4937cd4fdc2002c238de13cb89112dac32..36f6eb75e9533a9d5c064ca6e81c1e825d397c6e 100644
--- a/synapse/federation/transport/client.py
+++ b/synapse/federation/transport/client.py
@@ -525,6 +525,18 @@ class TransportLayerClient(object):
             ignore_backoff=True,
         )
 
+    def remove_room_from_group(self, destination, group_id, requester_user_id, room_id):
+        """Remove a room from a group
+        """
+        path = PREFIX + "/groups/%s/room/%s" % (group_id, room_id,)
+
+        return self.client.delete_json(
+            destination=destination,
+            path=path,
+            args={"requester_user_id": requester_user_id},
+            ignore_backoff=True,
+        )
+
     @log_function
     def get_users_in_group(self, destination, group_id, requester_user_id):
         """Get users in a group
diff --git a/synapse/federation/transport/server.py b/synapse/federation/transport/server.py
index b5f07c50bf102b83586c7d164741dcb221a7db34..c7565e073778dd8e0fd88ae137ccf850da4f24ce 100644
--- a/synapse/federation/transport/server.py
+++ b/synapse/federation/transport/server.py
@@ -674,7 +674,7 @@ class FederationGroupsRoomsServlet(BaseFederationServlet):
 
 
 class FederationGroupsAddRoomsServlet(BaseFederationServlet):
-    """Add room to group
+    """Add/remove room from group
     """
     PATH = "/groups/(?P<group_id>[^/]*)/room/(?<room_id>)$"
 
@@ -690,6 +690,18 @@ class FederationGroupsAddRoomsServlet(BaseFederationServlet):
 
         defer.returnValue((200, new_content))
 
+    @defer.inlineCallbacks
+    def on_DELETE(self, origin, content, query, group_id, room_id):
+        requester_user_id = parse_string_from_args(query, "requester_user_id")
+        if get_domain_from_id(requester_user_id) != origin:
+            raise SynapseError(403, "requester_user_id doesn't match origin")
+
+        new_content = yield self.handler.remove_room_from_group(
+            group_id, requester_user_id, room_id,
+        )
+
+        defer.returnValue((200, new_content))
+
 
 class FederationGroupsUsersServlet(BaseFederationServlet):
     """Get the users in a group on behalf of a user
diff --git a/synapse/groups/groups_server.py b/synapse/groups/groups_server.py
index 94cf9788bb1dc341fc94ced4a25cbedf26f81220..10bf61d178c41b090adca14f12de1a61ce330de7 100644
--- a/synapse/groups/groups_server.py
+++ b/synapse/groups/groups_server.py
@@ -466,14 +466,24 @@ class GroupsServerHandler(object):
             group_id, and_exists=True, and_is_admin=requester_user_id
         )
 
-        # TODO: Check if room has already been added
-
         is_public = _parse_visibility_from_contents(content)
 
         yield self.store.add_room_to_group(group_id, room_id, is_public=is_public)
 
         defer.returnValue({})
 
+    @defer.inlineCallbacks
+    def remove_room_from_group(self, group_id, requester_user_id, room_id):
+        """Remove room from group
+        """
+        yield self.check_group_is_ours(
+            group_id, and_exists=True, and_is_admin=requester_user_id
+        )
+
+        yield self.store.remove_room_from_group(group_id, room_id)
+
+        defer.returnValue({})
+
     @defer.inlineCallbacks
     def invite_to_group(self, group_id, user_id, requester_user_id, content):
         """Invite user to group
diff --git a/synapse/handlers/groups_local.py b/synapse/handlers/groups_local.py
index 14fdf06b5863e4761759601b932c54bbecd12e30..a2bacbfc38326b4486a8c270414d8ce49d75e7a3 100644
--- a/synapse/handlers/groups_local.py
+++ b/synapse/handlers/groups_local.py
@@ -69,6 +69,7 @@ class GroupsLocalHandler(object):
     get_rooms_in_group = _create_rerouter("get_rooms_in_group")
 
     add_room_to_group = _create_rerouter("add_room_to_group")
+    remove_room_from_group = _create_rerouter("remove_room_from_group")
 
     update_group_summary_room = _create_rerouter("update_group_summary_room")
     delete_group_summary_room = _create_rerouter("delete_group_summary_room")
diff --git a/synapse/rest/client/v2_alpha/groups.py b/synapse/rest/client/v2_alpha/groups.py
index b469058e9d5f1847af71be942a5996dc8a8f5550..8f3ce15b0220ee509055e84a28066f601f1a04fc 100644
--- a/synapse/rest/client/v2_alpha/groups.py
+++ b/synapse/rest/client/v2_alpha/groups.py
@@ -423,6 +423,17 @@ class GroupAdminRoomsServlet(RestServlet):
 
         defer.returnValue((200, result))
 
+    @defer.inlineCallbacks
+    def on_DELETE(self, request, group_id, room_id):
+        requester = yield self.auth.get_user_by_req(request)
+        user_id = requester.user.to_string()
+
+        result = yield self.groups_handler.remove_room_from_group(
+            group_id, user_id, room_id,
+        )
+
+        defer.returnValue((200, result))
+
 
 class GroupAdminUsersInviteServlet(RestServlet):
     """Invite a user to the group
diff --git a/synapse/storage/group_server.py b/synapse/storage/group_server.py
index d0b5ad231af060645680ba3c0af69418faee76e1..4fe9172adc2bc9b9e69aac2aa1bab21e110df910 100644
--- a/synapse/storage/group_server.py
+++ b/synapse/storage/group_server.py
@@ -843,6 +843,29 @@ class GroupServerStore(SQLBaseStore):
             desc="add_room_to_group",
         )
 
+    def remove_room_from_group(self, group_id, room_id):
+        def _remove_room_from_group_txn(txn):
+            self._simple_delete_txn(
+                txn,
+                table="group_rooms",
+                keyvalues={
+                    "group_id": group_id,
+                    "room_id": room_id,
+                },
+            )
+
+            self._simple_delete_txn(
+                txn,
+                table="group_summary_rooms",
+                keyvalues={
+                    "group_id": group_id,
+                    "room_id": room_id,
+                },
+            )
+        return self.runInteraction(
+            "remove_room_from_group", _remove_room_from_group_txn,
+        )
+
     def get_publicised_groups_for_user(self, user_id):
         """Get all groups a user is publicising
         """
diff --git a/synapse/storage/schema/delta/43/group_server.sql b/synapse/storage/schema/delta/43/group_server.sql
index e74554381f1768e148452dd230a640ffd88736a0..b2333848a0ea494b100c32c17521aaf35032b932 100644
--- a/synapse/storage/schema/delta/43/group_server.sql
+++ b/synapse/storage/schema/delta/43/group_server.sql
@@ -52,7 +52,7 @@ CREATE TABLE group_rooms (
     is_public BOOLEAN NOT NULL  -- whether the room can be seen by everyone
 );
 
-CREATE INDEX groups_rooms_g_idx ON group_rooms(group_id, room_id);
+CREATE UNIQUE INDEX groups_rooms_g_idx ON group_rooms(group_id, room_id);
 CREATE INDEX groups_rooms_r_idx ON group_rooms(room_id);