diff --git a/machine-learning/.gitignore b/machine-learning/.gitignore
index d3163ea5b0..a259b9f5dc 100644
--- a/machine-learning/.gitignore
+++ b/machine-learning/.gitignore
@@ -171,4 +171,6 @@ cython_debug/
 .vscode
 
 *.onnx
-*.zip
\ No newline at end of file
+*.zip
+
+core
\ No newline at end of file
diff --git a/server/src/domain/user/user.service.spec.ts b/server/src/domain/user/user.service.spec.ts
index cba4581562..dba0106fb6 100644
--- a/server/src/domain/user/user.service.spec.ts
+++ b/server/src/domain/user/user.service.spec.ts
@@ -8,7 +8,6 @@ import {
 import {
   authStub,
   newAlbumRepositoryMock,
-  newAssetRepositoryMock,
   newCryptoRepositoryMock,
   newJobRepositoryMock,
   newLibraryRepositoryMock,
@@ -23,7 +22,6 @@ import { CacheControl, ImmichFileResponse } from '../domain.util';
 import { JobName } from '../job';
 import {
   IAlbumRepository,
-  IAssetRepository,
   ICryptoRepository,
   IJobRepository,
   ILibraryRepository,
@@ -47,7 +45,6 @@ describe(UserService.name, () => {
   let cryptoRepositoryMock: jest.Mocked<ICryptoRepository>;
 
   let albumMock: jest.Mocked<IAlbumRepository>;
-  let assetMock: jest.Mocked<IAssetRepository>;
   let jobMock: jest.Mocked<IJobRepository>;
   let libraryMock: jest.Mocked<ILibraryRepository>;
   let storageMock: jest.Mocked<IStorageRepository>;
@@ -55,7 +52,6 @@ describe(UserService.name, () => {
 
   beforeEach(() => {
     albumMock = newAlbumRepositoryMock();
-    assetMock = newAssetRepositoryMock();
     configMock = newSystemConfigRepositoryMock();
     cryptoRepositoryMock = newCryptoRepositoryMock();
     jobMock = newJobRepositoryMock();
@@ -63,16 +59,7 @@ describe(UserService.name, () => {
     storageMock = newStorageRepositoryMock();
     userMock = newUserRepositoryMock();
 
-    sut = new UserService(
-      albumMock,
-      assetMock,
-      cryptoRepositoryMock,
-      jobMock,
-      libraryMock,
-      storageMock,
-      configMock,
-      userMock,
-    );
+    sut = new UserService(albumMock, cryptoRepositoryMock, jobMock, libraryMock, storageMock, configMock, userMock);
 
     when(userMock.get).calledWith(authStub.admin.user.id, {}).mockResolvedValue(userStub.admin);
     when(userMock.get).calledWith(authStub.admin.user.id, { withDeleted: true }).mockResolvedValue(userStub.admin);
@@ -537,7 +524,6 @@ describe(UserService.name, () => {
       expect(storageMock.unlinkDir).toHaveBeenCalledWith('upload/thumbs/deleted-user', options);
       expect(storageMock.unlinkDir).toHaveBeenCalledWith('upload/encoded-video/deleted-user', options);
       expect(albumMock.deleteAll).toHaveBeenCalledWith(user.id);
-      expect(assetMock.deleteAll).toHaveBeenCalledWith(user.id);
       expect(userMock.delete).toHaveBeenCalledWith(user, true);
     });
 
diff --git a/server/src/domain/user/user.service.ts b/server/src/domain/user/user.service.ts
index ace2fb5e17..9a862199b8 100644
--- a/server/src/domain/user/user.service.ts
+++ b/server/src/domain/user/user.service.ts
@@ -8,7 +8,6 @@ import { CacheControl, ImmichFileResponse } from '../domain.util';
 import { IEntityJob, JobName } from '../job';
 import {
   IAlbumRepository,
-  IAssetRepository,
   ICryptoRepository,
   IJobRepository,
   ILibraryRepository,
@@ -31,7 +30,6 @@ export class UserService {
 
   constructor(
     @Inject(IAlbumRepository) private albumRepository: IAlbumRepository,
-    @Inject(IAssetRepository) private assetRepository: IAssetRepository,
     @Inject(ICryptoRepository) cryptoRepository: ICryptoRepository,
     @Inject(IJobRepository) private jobRepository: IJobRepository,
     @Inject(ILibraryRepository) libraryRepository: ILibraryRepository,
@@ -185,9 +183,7 @@ export class UserService {
     }
 
     this.logger.warn(`Removing user from database: ${user.id}`);
-
     await this.albumRepository.deleteAll(user.id);
-    await this.assetRepository.deleteAll(user.id);
     await this.userRepository.delete(user, true);
 
     return true;
diff --git a/server/src/infra/entities/shared-link.entity.ts b/server/src/infra/entities/shared-link.entity.ts
index f64ad84249..e7cd19e53f 100644
--- a/server/src/infra/entities/shared-link.entity.ts
+++ b/server/src/infra/entities/shared-link.entity.ts
@@ -27,7 +27,7 @@ export class SharedLinkEntity {
   @Column()
   userId!: string;
 
-  @ManyToOne(() => UserEntity)
+  @ManyToOne(() => UserEntity, { onDelete: 'CASCADE', onUpdate: 'CASCADE' })
   user!: UserEntity;
 
   @Index('IDX_sharedlink_key')
diff --git a/server/src/infra/migrations/1709825430031-CascadeSharedLinksDelete.ts b/server/src/infra/migrations/1709825430031-CascadeSharedLinksDelete.ts
new file mode 100644
index 0000000000..9689741929
--- /dev/null
+++ b/server/src/infra/migrations/1709825430031-CascadeSharedLinksDelete.ts
@@ -0,0 +1,16 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class CascadeSharedLinksDelete1709825430031 implements MigrationInterface {
+    name = 'CascadeSharedLinksDelete1709825430031'
+
+    public async up(queryRunner: QueryRunner): Promise<void> {
+        await queryRunner.query(`ALTER TABLE "shared_links" DROP CONSTRAINT "FK_66fe3837414c5a9f1c33ca49340"`);
+        await queryRunner.query(`ALTER TABLE "shared_links" ADD CONSTRAINT "FK_66fe3837414c5a9f1c33ca49340" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE`);
+    }
+
+    public async down(queryRunner: QueryRunner): Promise<void> {
+        await queryRunner.query(`ALTER TABLE "shared_links" DROP CONSTRAINT "FK_66fe3837414c5a9f1c33ca49340"`);
+        await queryRunner.query(`ALTER TABLE "shared_links" ADD CONSTRAINT "FK_66fe3837414c5a9f1c33ca49340" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
+    }
+
+}