diff --git a/UPGRADE.rst b/UPGRADE.rst
index d00f718caecf72ed86f2f22db068e3f464666081..22edfe0d60440b9e92b3f86c5b446cfd32d0fb94 100644
--- a/UPGRADE.rst
+++ b/UPGRADE.rst
@@ -99,6 +99,10 @@ to the list of permitted "redirect URIs" at the identity provider.
 See `docs/openid.md <docs/openid.md>`_ for more information on setting up OpenID
 Connect.
 
+(Note: a similar change is being made for SAML2; in this case the old URI
+``[synapse public baseurl]/_matrix/saml2`` is being deprecated, but will continue to
+work, so no immediate changes are required for existing installations.)
+
 Changes to HTML templates
 -------------------------
 
diff --git a/changelog.d/9289.removal b/changelog.d/9289.removal
new file mode 100644
index 0000000000000000000000000000000000000000..49158fc4d352c53d9a7edcd41856a6303e6148b8
--- /dev/null
+++ b/changelog.d/9289.removal
@@ -0,0 +1 @@
+Add new endpoint `/_synapse/client/saml2` for SAML2 authentication callbacks, and deprecate the old endpoint `/_matrix/saml2`.
diff --git a/docs/sample_config.yaml b/docs/sample_config.yaml
index dd2981717d97694eefdc84824fc75904d71d4c80..6d265d29729c47e9843994b3c407be7588221cab 100644
--- a/docs/sample_config.yaml
+++ b/docs/sample_config.yaml
@@ -1566,10 +1566,10 @@ trusted_key_servers:
 # enable SAML login.
 #
 # Once SAML support is enabled, a metadata file will be exposed at
-# https://<server>:<port>/_matrix/saml2/metadata.xml, which you may be able to
+# https://<server>:<port>/_synapse/client/saml2/metadata.xml, which you may be able to
 # use to configure your SAML IdP with. Alternatively, you can manually configure
 # the IdP to use an ACS location of
-# https://<server>:<port>/_matrix/saml2/authn_response.
+# https://<server>:<port>/_synapse/client/saml2/authn_response.
 #
 saml2_config:
   # `sp_config` is the configuration for the pysaml2 Service Provider.
diff --git a/docs/workers.md b/docs/workers.md
index c4a6c79238bc8e9dd79bd8edf6765cfdd600dfe5..f7fc6df119eefc5329b945a2038a554965713d83 100644
--- a/docs/workers.md
+++ b/docs/workers.md
@@ -269,7 +269,7 @@ using):
     ^/_synapse/client/oidc/callback$
 
     # SAML requests.
-    ^/_matrix/saml2/authn_response$
+    ^/_synapse/client/saml2/authn_response$
 
     # CAS requests.
     ^/_matrix/client/(api/v1|r0|unstable)/login/cas/ticket$
diff --git a/synapse/config/saml2_config.py b/synapse/config/saml2_config.py
index f33dfa0d6a12147abfb1a93a475cce43daf9ae5c..ad865a667fdb03cb8add6805d910a29c7d86b230 100644
--- a/synapse/config/saml2_config.py
+++ b/synapse/config/saml2_config.py
@@ -194,8 +194,8 @@ class SAML2Config(Config):
             optional_attributes.add(self.saml2_grandfathered_mxid_source_attribute)
         optional_attributes -= required_attributes
 
-        metadata_url = public_baseurl + "_matrix/saml2/metadata.xml"
-        response_url = public_baseurl + "_matrix/saml2/authn_response"
+        metadata_url = public_baseurl + "_synapse/client/saml2/metadata.xml"
+        response_url = public_baseurl + "_synapse/client/saml2/authn_response"
         return {
             "entityid": metadata_url,
             "service": {
@@ -233,10 +233,10 @@ class SAML2Config(Config):
         # enable SAML login.
         #
         # Once SAML support is enabled, a metadata file will be exposed at
-        # https://<server>:<port>/_matrix/saml2/metadata.xml, which you may be able to
+        # https://<server>:<port>/_synapse/client/saml2/metadata.xml, which you may be able to
         # use to configure your SAML IdP with. Alternatively, you can manually configure
         # the IdP to use an ACS location of
-        # https://<server>:<port>/_matrix/saml2/authn_response.
+        # https://<server>:<port>/_synapse/client/saml2/authn_response.
         #
         saml2_config:
           # `sp_config` is the configuration for the pysaml2 Service Provider.
diff --git a/synapse/handlers/saml_handler.py b/synapse/handlers/saml_handler.py
index 5946919c33eec2cab4f003fd0f29ba3564db0c6c..e88fd5974939ac756da6e43fc550e039bf368213 100644
--- a/synapse/handlers/saml_handler.py
+++ b/synapse/handlers/saml_handler.py
@@ -133,7 +133,7 @@ class SamlHandler(BaseHandler):
         raise Exception("prepare_for_authenticate didn't return a Location header")
 
     async def handle_saml_response(self, request: SynapseRequest) -> None:
-        """Handle an incoming request to /_matrix/saml2/authn_response
+        """Handle an incoming request to /_synapse/client/saml2/authn_response
 
         Args:
             request: the incoming request from the browser. We'll
diff --git a/synapse/rest/synapse/client/__init__.py b/synapse/rest/synapse/client/__init__.py
index 381baf9729a3a71685c4232d77b84d9ccaf83259..e5ef515090b6c16ec1019b754beb09149e56cb55 100644
--- a/synapse/rest/synapse/client/__init__.py
+++ b/synapse/rest/synapse/client/__init__.py
@@ -52,10 +52,13 @@ def build_synapse_client_resource_tree(hs: "HomeServer") -> Mapping[str, Resourc
         resources["/_synapse/client/oidc"] = OIDCResource(hs)
 
     if hs.config.saml2_enabled:
-        from synapse.rest.saml2 import SAML2Resource
+        from synapse.rest.synapse.client.saml2 import SAML2Resource
 
-        # This is mounted under '/_matrix' for backwards-compatibility.
-        resources["/_matrix/saml2"] = SAML2Resource(hs)
+        res = SAML2Resource(hs)
+        resources["/_synapse/client/saml2"] = res
+
+        # This is also mounted under '/_matrix' for backwards-compatibility.
+        resources["/_matrix/saml2"] = res
 
     return resources
 
diff --git a/synapse/rest/saml2/__init__.py b/synapse/rest/synapse/client/saml2/__init__.py
similarity index 82%
rename from synapse/rest/saml2/__init__.py
rename to synapse/rest/synapse/client/saml2/__init__.py
index 68da37ca6a7abde7096d6e60a9d776113dfd6722..3e8235ee1e3780844e28524aa93b57ce5e9850fc 100644
--- a/synapse/rest/saml2/__init__.py
+++ b/synapse/rest/synapse/client/saml2/__init__.py
@@ -12,12 +12,13 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
+
 import logging
 
 from twisted.web.resource import Resource
 
-from synapse.rest.saml2.metadata_resource import SAML2MetadataResource
-from synapse.rest.saml2.response_resource import SAML2ResponseResource
+from synapse.rest.synapse.client.saml2.metadata_resource import SAML2MetadataResource
+from synapse.rest.synapse.client.saml2.response_resource import SAML2ResponseResource
 
 logger = logging.getLogger(__name__)
 
@@ -27,3 +28,6 @@ class SAML2Resource(Resource):
         Resource.__init__(self)
         self.putChild(b"metadata.xml", SAML2MetadataResource(hs))
         self.putChild(b"authn_response", SAML2ResponseResource(hs))
+
+
+__all__ = ["SAML2Resource"]
diff --git a/synapse/rest/saml2/metadata_resource.py b/synapse/rest/synapse/client/saml2/metadata_resource.py
similarity index 100%
rename from synapse/rest/saml2/metadata_resource.py
rename to synapse/rest/synapse/client/saml2/metadata_resource.py
diff --git a/synapse/rest/saml2/response_resource.py b/synapse/rest/synapse/client/saml2/response_resource.py
similarity index 100%
rename from synapse/rest/saml2/response_resource.py
rename to synapse/rest/synapse/client/saml2/response_resource.py