diff --git a/src/api/client_server/media.rs b/src/api/client_server/media.rs
index 0e70c1dc..7b492913 100644
--- a/src/api/client_server/media.rs
+++ b/src/api/client_server/media.rs
@@ -192,7 +192,7 @@ pub(crate) async fn get_content_route(body: Ruma<get_content::v3::Request>) -> R
 		content_disposition,
 	}) = services().media.get(mxc.clone()).await?
 	{
-		let content_disposition = Some(make_content_disposition(&file, &content_type, content_disposition));
+		let content_disposition = Some(make_content_disposition(&file, &content_type, content_disposition, None));
 		let content_type = Some(make_content_type(&file, &content_type).to_owned());
 
 		Ok(get_content::v3::Response {
@@ -220,6 +220,7 @@ pub(crate) async fn get_content_route(body: Ruma<get_content::v3::Request>) -> R
 			&response.file,
 			&response.content_type,
 			response.content_disposition,
+			None,
 		));
 		let content_type = Some(make_content_type(&response.file, &response.content_type).to_owned());
 
@@ -272,7 +273,12 @@ pub(crate) async fn get_content_as_filename_route(
 		content_disposition,
 	}) = services().media.get(mxc.clone()).await?
 	{
-		let content_disposition = Some(make_content_disposition(&file, &content_type, content_disposition));
+		let content_disposition = Some(make_content_disposition(
+			&file,
+			&content_type,
+			content_disposition,
+			Some(body.filename.clone()),
+		));
 		let content_type = Some(make_content_type(&file, &content_type).to_owned());
 
 		Ok(get_content_as_filename::v3::Response {
@@ -297,6 +303,7 @@ pub(crate) async fn get_content_as_filename_route(
 					&remote_content_response.file,
 					&remote_content_response.content_type,
 					remote_content_response.content_disposition,
+					None,
 				));
 				let content_type = Some(
 					make_content_type(&remote_content_response.file, &remote_content_response.content_type).to_owned(),
@@ -368,7 +375,7 @@ pub(crate) async fn get_content_thumbnail_route(
 		)
 		.await?
 	{
-		let content_disposition = Some(make_content_disposition(&file, &content_type, content_disposition));
+		let content_disposition = Some(make_content_disposition(&file, &content_type, content_disposition, None));
 		let content_type = Some(make_content_type(&file, &content_type).to_owned());
 
 		Ok(get_content_thumbnail::v3::Response {
@@ -425,6 +432,7 @@ pub(crate) async fn get_content_thumbnail_route(
 					&get_thumbnail_response.file,
 					&get_thumbnail_response.content_type,
 					get_thumbnail_response.content_disposition,
+					None,
 				));
 				let content_type = Some(
 					make_content_type(&get_thumbnail_response.file, &get_thumbnail_response.content_type).to_owned(),
@@ -498,6 +506,7 @@ async fn get_remote_content(
 		&content_response.file,
 		&content_response.content_type,
 		content_response.content_disposition,
+		None,
 	));
 
 	let content_type = Some(make_content_type(&content_response.file, &content_response.content_type).to_owned());
diff --git a/src/core/utils/content_disposition.rs b/src/core/utils/content_disposition.rs
index 85828be7..2a2a6d18 100644
--- a/src/core/utils/content_disposition.rs
+++ b/src/core/utils/content_disposition.rs
@@ -74,7 +74,8 @@ pub fn sanitise_filename(filename: String) -> String {
 }
 
 /// creates the final Content-Disposition based on whether the filename exists
-/// or not.
+/// or not, or if a requested filename was specified (media download with
+/// filename)
 ///
 /// if filename exists:
 /// `Content-Disposition: attachment/inline; filename=filename.ext`
@@ -82,19 +83,25 @@ pub fn sanitise_filename(filename: String) -> String {
 /// else: `Content-Disposition: attachment/inline`
 #[tracing::instrument(skip(file))]
 pub fn make_content_disposition(
-	file: &[u8], content_type: &Option<String>, content_disposition: Option<String>,
+	file: &[u8], content_type: &Option<String>, content_disposition: Option<String>, req_filename: Option<String>,
 ) -> String {
-	let filename = content_disposition.map_or_else(String::new, |content_disposition| {
-		let (_, filename) = content_disposition
-			.split_once("filename=")
-			.unwrap_or(("", ""));
+	let filename: String;
 
-		if filename.is_empty() {
-			String::new()
-		} else {
-			sanitise_filename(filename.to_owned())
-		}
-	});
+	if let Some(req_filename) = req_filename {
+		filename = sanitise_filename(req_filename);
+	} else {
+		filename = content_disposition.map_or_else(String::new, |content_disposition| {
+			let (_, filename) = content_disposition
+				.split_once("filename=")
+				.unwrap_or(("", ""));
+
+			if filename.is_empty() {
+				String::new()
+			} else {
+				sanitise_filename(filename.to_owned())
+			}
+		});
+	};
 
 	if !filename.is_empty() {
 		// Content-Disposition: attachment/inline; filename=filename.ext