diff --git a/e2e/src/api/specs/asset.e2e-spec.ts b/e2e/src/api/specs/asset.e2e-spec.ts
index ec09d71d21..32cbdd6df8 100644
--- a/e2e/src/api/specs/asset.e2e-spec.ts
+++ b/e2e/src/api/specs/asset.e2e-spec.ts
@@ -3,11 +3,11 @@ import {
   AssetMediaStatus,
   AssetResponseDto,
   AssetTypeEnum,
-  LoginResponseDto,
-  SharedLinkType,
   getAssetInfo,
   getConfig,
   getMyUser,
+  LoginResponseDto,
+  SharedLinkType,
   updateConfig,
 } from '@immich/sdk';
 import { exiftool } from 'exiftool-vendored';
@@ -19,7 +19,7 @@ import { Socket } from 'socket.io-client';
 import { createUserDto, uuidDto } from 'src/fixtures';
 import { makeRandomImage } from 'src/generators';
 import { errorDto } from 'src/responses';
-import { app, asBearerAuth, tempDir, testAssetDir, utils } from 'src/utils';
+import { app, asBearerAuth, tempDir, TEN_TIMES, testAssetDir, utils } from 'src/utils';
 import request from 'supertest';
 import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
@@ -41,8 +41,6 @@ const makeUploadDto = (options?: { omit: string }): Record<string, any> => {
   return dto;
 };
 
-const TEN_TIMES = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
-
 const locationAssetFilepath = `${testAssetDir}/metadata/gps-position/thompson-springs.jpg`;
 const ratingAssetFilepath = `${testAssetDir}/metadata/rating/mongolels.jpg`;
 const facesAssetFilepath = `${testAssetDir}/metadata/faces/portrait.jpg`;
diff --git a/e2e/src/api/specs/search.e2e-spec.ts b/e2e/src/api/specs/search.e2e-spec.ts
index 11bb37be18..50fce29ce0 100644
--- a/e2e/src/api/specs/search.e2e-spec.ts
+++ b/e2e/src/api/specs/search.e2e-spec.ts
@@ -1,10 +1,10 @@
-import { AssetMediaResponseDto, LoginResponseDto, deleteAssets, updateAsset } from '@immich/sdk';
+import { AssetMediaResponseDto, AssetResponseDto, deleteAssets, LoginResponseDto, updateAsset } from '@immich/sdk';
 import { DateTime } from 'luxon';
 import { readFile } from 'node:fs/promises';
 import { join } from 'node:path';
 import { Socket } from 'socket.io-client';
 import { errorDto } from 'src/responses';
-import { app, asBearerAuth, testAssetDir, utils } from 'src/utils';
+import { app, asBearerAuth, TEN_TIMES, testAssetDir, utils } from 'src/utils';
 import request from 'supertest';
 import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 const today = DateTime.now();
@@ -462,6 +462,55 @@ describe('/search', () => {
     });
   });
 
+  describe('POST /search/random', () => {
+    beforeAll(async () => {
+      await Promise.all([
+        utils.createAsset(admin.accessToken),
+        utils.createAsset(admin.accessToken),
+        utils.createAsset(admin.accessToken),
+        utils.createAsset(admin.accessToken),
+        utils.createAsset(admin.accessToken),
+        utils.createAsset(admin.accessToken),
+      ]);
+
+      await utils.waitForQueueFinish(admin.accessToken, 'thumbnailGeneration');
+    });
+
+    it('should require authentication', async () => {
+      const { status, body } = await request(app).post('/search/random').send({ size: 1 });
+
+      expect(status).toBe(401);
+      expect(body).toEqual(errorDto.unauthorized);
+    });
+
+    it.each(TEN_TIMES)('should return 1 random assets', async () => {
+      const { status, body } = await request(app)
+        .post('/search/random')
+        .send({ size: 1 })
+        .set('Authorization', `Bearer ${admin.accessToken}`);
+
+      expect(status).toBe(200);
+
+      const assets: AssetResponseDto[] = body;
+      expect(assets.length).toBe(1);
+      expect(assets[0].ownerId).toBe(admin.userId);
+    });
+
+    it.each(TEN_TIMES)('should return 2 random assets', async () => {
+      const { status, body } = await request(app)
+        .post('/search/random')
+        .send({ size: 2 })
+        .set('Authorization', `Bearer ${admin.accessToken}`);
+
+      expect(status).toBe(200);
+
+      const assets: AssetResponseDto[] = body;
+      expect(assets.length).toBe(2);
+      expect(assets[0].ownerId).toBe(admin.userId);
+      expect(assets[1].ownerId).toBe(admin.userId);
+    });
+  });
+
   describe('GET /search/explore', () => {
     it('should require authentication', async () => {
       const { status, body } = await request(app).get('/search/explore');
diff --git a/e2e/src/utils.ts b/e2e/src/utils.ts
index 7b80ba49aa..efd9ce76b9 100644
--- a/e2e/src/utils.ts
+++ b/e2e/src/utils.ts
@@ -76,6 +76,7 @@ export const immichCli = (args: string[]) =>
 export const immichAdmin = (args: string[]) =>
   executeCommand('docker', ['exec', '-i', 'immich-e2e-server', '/bin/bash', '-c', `immich-admin ${args.join(' ')}`]);
 export const specialCharStrings = ["'", '"', ',', '{', '}', '*'];
+export const TEN_TIMES = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
 
 const executeCommand = (command: string, args: string[]) => {
   let _resolve: (value: CommandResponse) => void;
diff --git a/server/src/queries/search.repository.sql b/server/src/queries/search.repository.sql
index 1e50943781..2d5da4d381 100644
--- a/server/src/queries/search.repository.sql
+++ b/server/src/queries/search.repository.sql
@@ -60,6 +60,8 @@ union all
   limit
     $14
 )
+limit
+  $15
 
 -- SearchRepository.searchSmart
 select
diff --git a/server/src/repositories/search.repository.ts b/server/src/repositories/search.repository.ts
index 9abee70de3..fb59157c80 100644
--- a/server/src/repositories/search.repository.ts
+++ b/server/src/repositories/search.repository.ts
@@ -69,12 +69,13 @@ export class SearchRepository implements ISearchRepository {
       },
     ],
   })
-  searchRandom(size: number, options: AssetSearchOptions): Promise<AssetEntity[]> {
+  async searchRandom(size: number, options: AssetSearchOptions): Promise<AssetEntity[]> {
     const uuid = randomUUID();
     const builder = searchAssetBuilder(this.db, options);
     const lessThan = builder.where('assets.id', '<', uuid).orderBy('assets.id').limit(size);
     const greaterThan = builder.where('assets.id', '>', uuid).orderBy('assets.id').limit(size);
-    return sql`${lessThan} union all ${greaterThan}`.execute(this.db) as any as Promise<AssetEntity[]>;
+    const { rows } = await sql`${lessThan} union all ${greaterThan} limit ${size}`.execute(this.db);
+    return rows as any as AssetEntity[];
   }
 
   @GenerateSql({