diff --git a/server/src/domain/repositories/storage.repository.ts b/server/src/domain/repositories/storage.repository.ts
index c55aaf7ecd..bdd23ccabe 100644
--- a/server/src/domain/repositories/storage.repository.ts
+++ b/server/src/domain/repositories/storage.repository.ts
@@ -42,4 +42,5 @@ export interface IStorageRepository {
   copyFile(source: string, target: string): Promise<void>;
   rename(source: string, target: string): Promise<void>;
   watch(paths: string[], options: WatchOptions): ImmichWatcher;
+  utimes(filepath: string, atime: Date, mtime: Date): Promise<void>;
 }
diff --git a/server/src/domain/storage-template/storage-template.service.spec.ts b/server/src/domain/storage-template/storage-template.service.spec.ts
index 6e17ca64e9..67d2bd2226 100644
--- a/server/src/domain/storage-template/storage-template.service.spec.ts
+++ b/server/src/domain/storage-template/storage-template.service.spec.ts
@@ -534,6 +534,12 @@ describe(StorageTemplateService.name, () => {
         .mockResolvedValue({
           size: 5000,
         } as Stats);
+      when(storageMock.stat)
+        .calledWith(assetStub.image.originalPath)
+        .mockResolvedValue({
+          atime: new Date(),
+          mtime: new Date(),
+        } as Stats);
       when(cryptoMock.hashFile).calledWith(newPath).mockResolvedValue(assetStub.image.checksum);
 
       await sut.handleMigration();
@@ -542,6 +548,8 @@ describe(StorageTemplateService.name, () => {
       expect(storageMock.rename).toHaveBeenCalledWith('/original/path.jpg', newPath);
       expect(storageMock.copyFile).toHaveBeenCalledWith('/original/path.jpg', newPath);
       expect(storageMock.stat).toHaveBeenCalledWith(newPath);
+      expect(storageMock.stat).toHaveBeenCalledWith(assetStub.image.originalPath);
+      expect(storageMock.utimes).toHaveBeenCalledWith(newPath, expect.any(Date), expect.any(Date));
       expect(storageMock.unlink).toHaveBeenCalledWith(assetStub.image.originalPath);
       expect(storageMock.unlink).toHaveBeenCalledTimes(1);
       expect(assetMock.save).toHaveBeenCalledWith({
diff --git a/server/src/domain/storage/storage.core.ts b/server/src/domain/storage/storage.core.ts
index 9456fd66b1..30a6002be5 100644
--- a/server/src/domain/storage/storage.core.ts
+++ b/server/src/domain/storage/storage.core.ts
@@ -222,6 +222,9 @@ export class StorageCore {
           return;
         }
 
+        const { atime, mtime } = await this.repository.stat(move.oldPath);
+        await this.repository.utimes(newPath, atime, mtime);
+
         try {
           await this.repository.unlink(move.oldPath);
         } catch (error: any) {
diff --git a/server/src/immich/api-v1/asset/asset.service.spec.ts b/server/src/immich/api-v1/asset/asset.service.spec.ts
index 0e5bafa5f0..9f0aa371e8 100644
--- a/server/src/immich/api-v1/asset/asset.service.spec.ts
+++ b/server/src/immich/api-v1/asset/asset.service.spec.ts
@@ -1,4 +1,11 @@
-import { IAssetRepository, IJobRepository, ILibraryRepository, IUserRepository, JobName } from '@app/domain';
+import {
+  IAssetRepository,
+  IJobRepository,
+  ILibraryRepository,
+  IStorageRepository,
+  IUserRepository,
+  JobName,
+} from '@app/domain';
 import { ASSET_CHECKSUM_CONSTRAINT, AssetEntity, AssetType, ExifEntity } from '@app/infra/entities';
 import {
   IAccessRepositoryMock,
@@ -9,6 +16,7 @@ import {
   newAssetRepositoryMock,
   newJobRepositoryMock,
   newLibraryRepositoryMock,
+  newStorageRepositoryMock,
   newUserRepositoryMock,
 } from '@test';
 import { when } from 'jest-when';
@@ -63,6 +71,7 @@ describe('AssetService', () => {
   let assetMock: jest.Mocked<IAssetRepository>;
   let jobMock: jest.Mocked<IJobRepository>;
   let libraryMock: jest.Mocked<ILibraryRepository>;
+  let storageMock: jest.Mocked<IStorageRepository>;
   let userMock: jest.Mocked<IUserRepository>;
 
   beforeEach(() => {
@@ -81,9 +90,10 @@ describe('AssetService', () => {
     assetMock = newAssetRepositoryMock();
     jobMock = newJobRepositoryMock();
     libraryMock = newLibraryRepositoryMock();
+    storageMock = newStorageRepositoryMock();
     userMock = newUserRepositoryMock();
 
-    sut = new AssetService(accessMock, assetRepositoryMockV1, assetMock, jobMock, libraryMock, userMock);
+    sut = new AssetService(accessMock, assetRepositoryMockV1, assetMock, jobMock, libraryMock, storageMock, userMock);
 
     when(assetRepositoryMockV1.get)
       .calledWith(assetStub.livePhotoStillAsset.id)
@@ -113,6 +123,11 @@ describe('AssetService', () => {
 
       expect(assetMock.create).toHaveBeenCalled();
       expect(userMock.updateUsage).toHaveBeenCalledWith(authStub.user1.user.id, file.size);
+      expect(storageMock.utimes).toHaveBeenCalledWith(
+        file.originalPath,
+        expect.any(Date),
+        new Date(dto.fileModifiedAt),
+      );
     });
 
     it('should handle a duplicate', async () => {
@@ -167,6 +182,16 @@ describe('AssetService', () => {
         [{ name: JobName.METADATA_EXTRACTION, data: { id: assetStub.livePhotoStillAsset.id, source: 'upload' } }],
       ]);
       expect(userMock.updateUsage).toHaveBeenCalledWith(authStub.user1.user.id, 111);
+      expect(storageMock.utimes).toHaveBeenCalledWith(
+        fileStub.livePhotoStill.originalPath,
+        expect.any(Date),
+        new Date(dto.fileModifiedAt),
+      );
+      expect(storageMock.utimes).toHaveBeenCalledWith(
+        fileStub.livePhotoMotion.originalPath,
+        expect.any(Date),
+        new Date(dto.fileModifiedAt),
+      );
     });
   });
 
diff --git a/server/src/immich/api-v1/asset/asset.service.ts b/server/src/immich/api-v1/asset/asset.service.ts
index b0ff311c51..f438e55e9c 100644
--- a/server/src/immich/api-v1/asset/asset.service.ts
+++ b/server/src/immich/api-v1/asset/asset.service.ts
@@ -7,6 +7,7 @@ import {
   IAssetRepository,
   IJobRepository,
   ILibraryRepository,
+  IStorageRepository,
   IUserRepository,
   ImmichFileResponse,
   JobName,
@@ -55,6 +56,7 @@ export class AssetService {
     @Inject(IAssetRepository) private assetRepository: IAssetRepository,
     @Inject(IJobRepository) private jobRepository: IJobRepository,
     @Inject(ILibraryRepository) private libraryRepository: ILibraryRepository,
+    @Inject(IStorageRepository) private storageRepository: IStorageRepository,
     @Inject(IUserRepository) private userRepository: IUserRepository,
   ) {
     this.access = AccessCore.create(accessRepository);
@@ -358,6 +360,10 @@ export class AssetService {
       isOffline: dto.isOffline ?? false,
     });
 
+    if (sidecarPath) {
+      await this.storageRepository.utimes(sidecarPath, new Date(), new Date(dto.fileModifiedAt));
+    }
+    await this.storageRepository.utimes(file.originalPath, new Date(), new Date(dto.fileModifiedAt));
     await this.assetRepository.upsertExif({ assetId: asset.id, fileSizeInByte: file.size });
     await this.jobRepository.queue({ name: JobName.METADATA_EXTRACTION, data: { id: asset.id, source: 'upload' } });
 
diff --git a/server/src/infra/repositories/filesystem.provider.ts b/server/src/infra/repositories/filesystem.provider.ts
index 2ae18432b2..fa027ad465 100644
--- a/server/src/infra/repositories/filesystem.provider.ts
+++ b/server/src/infra/repositories/filesystem.provider.ts
@@ -12,7 +12,7 @@ import archiver from 'archiver';
 import chokidar, { WatchOptions } from 'chokidar';
 import { glob } from 'glob';
 import { constants, createReadStream, existsSync, mkdirSync } from 'node:fs';
-import fs, { copyFile, readdir, rename, writeFile } from 'node:fs/promises';
+import fs, { copyFile, readdir, rename, utimes, writeFile } from 'node:fs/promises';
 import path from 'node:path';
 
 export class FilesystemProvider implements IStorageRepository {
@@ -56,6 +56,8 @@ export class FilesystemProvider implements IStorageRepository {
 
   copyFile = copyFile;
 
+  utimes = utimes;
+
   async checkFileExists(filepath: string, mode = constants.F_OK): Promise<boolean> {
     try {
       await fs.access(filepath, mode);
diff --git a/server/test/repositories/storage.repository.mock.ts b/server/test/repositories/storage.repository.mock.ts
index f4dbc0c5b1..9df450f001 100644
--- a/server/test/repositories/storage.repository.mock.ts
+++ b/server/test/repositories/storage.repository.mock.ts
@@ -22,5 +22,6 @@ export const newStorageRepositoryMock = (reset = true): jest.Mocked<IStorageRepo
     rename: jest.fn(),
     copyFile: jest.fn(),
     watch: jest.fn(),
+    utimes: jest.fn(),
   };
 };