diff --git a/packages/astro/src/vite-plugin-astro-server/index.ts b/packages/astro/src/vite-plugin-astro-server/index.ts
index a71d6d7889..00461c9bb5 100644
--- a/packages/astro/src/vite-plugin-astro-server/index.ts
+++ b/packages/astro/src/vite-plugin-astro-server/index.ts
@@ -166,8 +166,10 @@ async function handle500Response(
 }
 
 function getCustom404Route(config: AstroConfig, manifest: ManifestData) {
+	// For Windows compat, use relative page paths to match the 404 route
 	const relPages = resolvePages(config).href.replace(config.root.href, '');
-	return manifest.routes.find((r) => r.component === appendForwardSlash(relPages) + '404.astro');
+	const pattern = new RegExp(`${appendForwardSlash(relPages)}404.(astro|md)`);
+	return manifest.routes.find((r) => r.component.match(pattern));
 }
 
 function log404(logging: LogOptions, pathname: string) {
diff --git a/packages/astro/test/custom-404-md.test.js b/packages/astro/test/custom-404-md.test.js
new file mode 100644
index 0000000000..69eddb26b7
--- /dev/null
+++ b/packages/astro/test/custom-404-md.test.js
@@ -0,0 +1,40 @@
+import { expect } from 'chai';
+import * as cheerio from 'cheerio';
+import { loadFixture } from './test-utils.js';
+
+describe('Custom 404 Markdown', () => {
+	let fixture;
+
+	before(async () => {
+		fixture = await loadFixture({
+			root: './fixtures/custom-404-md/',
+		});
+	});
+
+	describe('dev', () => {
+		let devServer;
+		let $;
+
+		before(async () => {
+			devServer = await fixture.startDevServer();
+		});
+
+		after(async () => {
+			await devServer.stop();
+		});
+
+		it('renders /', async () => {
+			const html = await fixture.fetch('/').then((res) => res.text());
+			$ = cheerio.load(html);
+
+			expect($('h1').text()).to.equal('Home');
+		});
+
+		it('renders 404 for /abc', async () => {
+			const html = await fixture.fetch('/a').then((res) => res.text());
+			$ = cheerio.load(html);
+
+			expect($('h1').text()).to.equal('Page not found');
+		});
+	});
+});
diff --git a/packages/astro/test/fixtures/custom-404-md/astro.config.mjs b/packages/astro/test/fixtures/custom-404-md/astro.config.mjs
new file mode 100644
index 0000000000..882e6515a6
--- /dev/null
+++ b/packages/astro/test/fixtures/custom-404-md/astro.config.mjs
@@ -0,0 +1,4 @@
+import { defineConfig } from 'astro/config';
+
+// https://astro.build/config
+export default defineConfig({});
diff --git a/packages/astro/test/fixtures/custom-404-md/package.json b/packages/astro/test/fixtures/custom-404-md/package.json
new file mode 100644
index 0000000000..4f6a0b25fa
--- /dev/null
+++ b/packages/astro/test/fixtures/custom-404-md/package.json
@@ -0,0 +1,8 @@
+{
+  "name": "@test/custom-404-md",
+  "version": "0.0.0",
+  "private": true,
+  "dependencies": {
+    "astro": "workspace:*"
+  }
+}
diff --git a/packages/astro/test/fixtures/custom-404-md/src/layouts/Base.astro b/packages/astro/test/fixtures/custom-404-md/src/layouts/Base.astro
new file mode 100644
index 0000000000..971e10ff1d
--- /dev/null
+++ b/packages/astro/test/fixtures/custom-404-md/src/layouts/Base.astro
@@ -0,0 +1,12 @@
+---
+const { content } = Astro.props;
+---
+
+<html lang="en">
+<head>
+  <title>{content.title}</title>
+</head>
+<body>
+	<slot />
+</body>
+</html>
diff --git a/packages/astro/test/fixtures/custom-404-md/src/pages/404.md b/packages/astro/test/fixtures/custom-404-md/src/pages/404.md
new file mode 100644
index 0000000000..c165ec9c3d
--- /dev/null
+++ b/packages/astro/test/fixtures/custom-404-md/src/pages/404.md
@@ -0,0 +1,6 @@
+---
+layout: '../layouts/Base.astro'
+title: 'Not Found - Custom 404'
+---
+
+# Page not found
diff --git a/packages/astro/test/fixtures/custom-404-md/src/pages/index.astro b/packages/astro/test/fixtures/custom-404-md/src/pages/index.astro
new file mode 100644
index 0000000000..cf5ef9b586
--- /dev/null
+++ b/packages/astro/test/fixtures/custom-404-md/src/pages/index.astro
@@ -0,0 +1,11 @@
+---
+---
+
+<html lang="en">
+<head>
+  <title>Custom 404</title>
+</head>
+<body>
+  <h1>Home</h1>
+</body>
+</html>
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 7e50bfd884..f63f0d7041 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1017,6 +1017,12 @@ importers:
     dependencies:
       astro: link:../../..
 
+  packages/astro/test/fixtures/custom-404-md:
+    specifiers:
+      astro: workspace:*
+    dependencies:
+      astro: link:../../..
+
   packages/astro/test/fixtures/custom-elements:
     specifiers:
       '@test/custom-element-renderer': workspace:*