diff --git a/CHANGELOG.md b/CHANGELOG.md
index 975aff3aeaf4b8bedb9ee2bce94e21d13f58f330..4b7fd4cb04dbc5a042e53a6902370af8f34b33c9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@ ChangeLog
 
 unreleased
 ----------
+* アカウントの削除を試験的に実装
 * デッキでメディア投稿のみ表示するオプションが機能していない問題を修正
 * デッキでユーザーを表示したときにタイムラインが残存する問題を修正
 * モバイルのユーザーページで、ユーザーAのタイムラインから他のユーザーBを選択してユーザーBのタイムラインに移動したとき、ユーザーAのタイムラインが残る問題を修正
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 8f4e1e4b293e63a2b1475c8e815437017194ab58..67f847a61f4716860cc74bb9bc9e077d42c308ef 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -589,6 +589,10 @@ common/views/components/profile-editor.vue:
     mute-list: "ミュート"
     blocking-list: "ブロック"
   export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
+  enter-password: "パスワードを入力してください"
+  danger-zone: "危険な設定"
+  delete-account: "アカウントを削除"
+  account-deleted: "アカウントが削除されました。データが消えるまで時間がかかる場合があります。"
 
 common/views/components/user-list-editor.vue:
   users: "ユーザー"
diff --git a/src/client/app/common/views/components/profile-editor.vue b/src/client/app/common/views/components/profile-editor.vue
index 929e4738b43dc34c62b58368c17cb715c9663706..91f6e91b33d373e5e2b8ff7b209a5ddb903f32cd 100644
--- a/src/client/app/common/views/components/profile-editor.vue
+++ b/src/client/app/common/views/components/profile-editor.vue
@@ -101,6 +101,13 @@
 			<ui-button @click="doExport()"><fa :icon="faDownload"/> {{ $t('export') }}</ui-button>
 		</div>
 	</section>
+
+	<section>
+		<details>
+			<summary>{{ $t('danger-zone') }}</summary>
+			<ui-button @click="deleteAccount()">{{ $t('delete-account') }}</ui-button>
+		</details>
+	</section>
 </ui-card>
 </template>
 
@@ -283,6 +290,25 @@ export default Vue.extend({
 				type: 'info',
 				text: this.$t('export-requested')
 			});
+		},
+
+		async deleteAccount() {
+			const { canceled: canceled, result: password } = await this.$root.dialog({
+				title: this.$t('enter-password'),
+				input: {
+					type: 'password'
+				}
+			});
+			if (canceled) return;
+
+			this.$root.api('i/delete-account', {
+				password
+			}).then(() => {
+				this.$root.dialog({
+					type: 'success',
+					text: this.$t('account-deleted')
+				});
+			});
 		}
 	}
 });
diff --git a/src/models/user.ts b/src/models/user.ts
index 2549b2568ad9ba76dc29c00257080760bce9ea85..6d187b310c5a7cdaf66732630a55066a5e3aeeaa 100644
--- a/src/models/user.ts
+++ b/src/models/user.ts
@@ -55,6 +55,8 @@ type IUserBase = {
 	emojis?: string[];
 	tags?: string[];
 
+	isDeleted: boolean;
+
 	/**
 	 * 凍結されているか否か
 	 */
diff --git a/src/queue/index.ts b/src/queue/index.ts
index 7dc2319f506b3205ad6f526328e1edd9945690db..9f874fea04b9a29e0829b339431a63485efedb44 100644
--- a/src/queue/index.ts
+++ b/src/queue/index.ts
@@ -70,6 +70,32 @@ export function processInbox(activity: any, signature: httpSignature.IParsedSign
 	}
 }
 
+export function createDeleteNotesJob(user: ILocalUser) {
+	const data = {
+		type: 'deleteNotes',
+		user: user
+	};
+
+	if (queueAvailable && enableQueueProcessing) {
+		return queue.createJob(data).save();
+	} else {
+		return handler({ data }, () => {});
+	}
+}
+
+export function createDeleteDriveFilesJob(user: ILocalUser) {
+	const data = {
+		type: 'deleteDriveFiles',
+		user: user
+	};
+
+	if (queueAvailable && enableQueueProcessing) {
+		return queue.createJob(data).save();
+	} else {
+		return handler({ data }, () => {});
+	}
+}
+
 export function createExportNotesJob(user: ILocalUser) {
 	const data = {
 		type: 'exportNotes',
diff --git a/src/queue/processors/delete-drive-files.ts b/src/queue/processors/delete-drive-files.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7e76aa73e6fe37da14fb9c27728faf8c5f70adcd
--- /dev/null
+++ b/src/queue/processors/delete-drive-files.ts
@@ -0,0 +1,55 @@
+import * as bq from 'bee-queue';
+import * as mongo from 'mongodb';
+
+import { queueLogger } from '../logger';
+import User from '../../models/user';
+import DriveFile from '../../models/drive-file';
+import deleteFile from '../../services/drive/delete-file';
+
+const logger = queueLogger.createSubLogger('delete-drive-files');
+
+export async function deleteDriveFiles(job: bq.Job, done: any): Promise<void> {
+	logger.info(`Deleting drive files of ${job.data.user._id} ...`);
+
+	const user = await User.findOne({
+		_id: new mongo.ObjectID(job.data.user._id.toString())
+	});
+
+	let deletedCount = 0;
+	let ended = false;
+	let cursor: any = null;
+
+	while (!ended) {
+		const files = await DriveFile.find({
+			userId: user._id,
+			...(cursor ? { _id: { $gt: cursor } } : {})
+		}, {
+			limit: 100,
+			sort: {
+				_id: 1
+			}
+		});
+
+		if (files.length === 0) {
+			ended = true;
+			if (job.reportProgress) job.reportProgress(100);
+			break;
+		}
+
+		cursor = files[files.length - 1]._id;
+
+		for (const file of files) {
+			await deleteFile(file);
+			deletedCount++;
+		}
+
+		const total = await DriveFile.count({
+			userId: user._id,
+		});
+
+		if (job.reportProgress) job.reportProgress(deletedCount / total);
+	}
+
+	logger.succ(`All drive files (${deletedCount}) of ${user._id} has been deleted.`);
+	done();
+}
diff --git a/src/queue/processors/delete-notes.ts b/src/queue/processors/delete-notes.ts
new file mode 100644
index 0000000000000000000000000000000000000000..13c6042b1630ef8889fa0a42c11736c79ac22d4e
--- /dev/null
+++ b/src/queue/processors/delete-notes.ts
@@ -0,0 +1,55 @@
+import * as bq from 'bee-queue';
+import * as mongo from 'mongodb';
+
+import { queueLogger } from '../logger';
+import Note from '../../models/note';
+import deleteNote from '../../services/note/delete';
+import User from '../../models/user';
+
+const logger = queueLogger.createSubLogger('delete-notes');
+
+export async function deleteNotes(job: bq.Job, done: any): Promise<void> {
+	logger.info(`Deleting notes of ${job.data.user._id} ...`);
+
+	const user = await User.findOne({
+		_id: new mongo.ObjectID(job.data.user._id.toString())
+	});
+
+	let deletedCount = 0;
+	let ended = false;
+	let cursor: any = null;
+
+	while (!ended) {
+		const notes = await Note.find({
+			userId: user._id,
+			...(cursor ? { _id: { $gt: cursor } } : {})
+		}, {
+			limit: 100,
+			sort: {
+				_id: 1
+			}
+		});
+
+		if (notes.length === 0) {
+			ended = true;
+			if (job.reportProgress) job.reportProgress(100);
+			break;
+		}
+
+		cursor = notes[notes.length - 1]._id;
+
+		for (const note of notes) {
+			await deleteNote(user, note, true);
+			deletedCount++;
+		}
+
+		const total = await Note.count({
+			userId: user._id,
+		});
+
+		if (job.reportProgress) job.reportProgress(deletedCount / total);
+	}
+
+	logger.succ(`All notes (${deletedCount}) of ${user._id} has been deleted.`);
+	done();
+}
diff --git a/src/queue/processors/index.ts b/src/queue/processors/index.ts
index 6869983205919284049166af8ade2ec96df4a493..31e87c3f67baa51b5ad0d9393512bbdc0f807d01 100644
--- a/src/queue/processors/index.ts
+++ b/src/queue/processors/index.ts
@@ -1,5 +1,7 @@
 import deliver from './http/deliver';
 import processInbox from './http/process-inbox';
+import { deleteNotes } from './delete-notes';
+import { deleteDriveFiles } from './delete-drive-files';
 import { exportNotes } from './export-notes';
 import { exportFollowing } from './export-following';
 import { exportMute } from './export-mute';
@@ -9,6 +11,8 @@ import { queueLogger } from '../logger';
 const handlers: any = {
 	deliver,
 	processInbox,
+	deleteNotes,
+	deleteDriveFiles,
 	exportNotes,
 	exportFollowing,
 	exportMute,
diff --git a/src/server/api/endpoints/i/delete-account.ts b/src/server/api/endpoints/i/delete-account.ts
new file mode 100644
index 0000000000000000000000000000000000000000..217ad0010b8e1eb3fa7133c23a815e2da10f7a8d
--- /dev/null
+++ b/src/server/api/endpoints/i/delete-account.ts
@@ -0,0 +1,49 @@
+import $ from 'cafy';
+import * as bcrypt from 'bcryptjs';
+import User from '../../../../models/user';
+import define from '../../define';
+import { createDeleteNotesJob, createDeleteDriveFilesJob } from '../../../../queue';
+
+export const meta = {
+	requireCredential: true,
+
+	secure: true,
+
+	params: {
+		password: {
+			validator: $.str
+		},
+	}
+};
+
+export default define(meta, (ps, user) => new Promise(async (res, rej) => {
+	// Compare password
+	const same = await bcrypt.compare(ps.password, user.password);
+
+	if (!same) {
+		return rej('incorrect password');
+	}
+
+	await User.update({ _id: user._id }, {
+		$set: {
+			isDeleted: true,
+			token: null,
+			name: null,
+			description: null,
+			pinnedNoteIds: [],
+			password: null,
+			email: null,
+			twitter: null,
+			github: null,
+			discord: null,
+			profile: {},
+			fields: [],
+			clientSettings: {},
+		}
+	});
+
+	createDeleteNotesJob(user);
+	createDeleteDriveFilesJob(user);
+
+	res();
+}));
diff --git a/src/services/note/delete.ts b/src/services/note/delete.ts
index 2b797545eda2eeca229b1b25d58c5acbe287cd85..efea46bca66388abb7b3d59398878723c3df1527 100644
--- a/src/services/note/delete.ts
+++ b/src/services/note/delete.ts
@@ -21,7 +21,7 @@ import instanceChart from '../../services/chart/instance';
  * @param user 投稿者
  * @param note 投稿
  */
-export default async function(user: IUser, note: INote) {
+export default async function(user: IUser, note: INote, quiet = false) {
 	const deletedAt = new Date();
 
 	await Note.update({
@@ -52,10 +52,6 @@ export default async function(user: IUser, note: INote) {
 		});
 	}
 
-	publishNoteStream(note._id, 'deleted', {
-		deletedAt: deletedAt
-	});
-
 	// この投稿が関わる未読通知を削除
 	NoteUnread.find({
 		noteId: note._id
@@ -76,34 +72,40 @@ export default async function(user: IUser, note: INote) {
 		}
 	}
 
-	//#region ローカルの投稿なら削除アクティビティを配送
-	if (isLocalUser(user)) {
-		const content = renderActivity(renderDelete(renderTombstone(`${config.url}/notes/${note._id}`), user));
-
-		const followings = await Following.find({
-			followeeId: user._id,
-			'_follower.host': { $ne: null }
+	if (!quiet) {
+		publishNoteStream(note._id, 'deleted', {
+			deletedAt: deletedAt
 		});
 
-		for (const following of followings) {
-			deliver(user, content, following._follower.inbox);
+		//#region ローカルの投稿なら削除アクティビティを配送
+		if (isLocalUser(user)) {
+			const content = renderActivity(renderDelete(renderTombstone(`${config.url}/notes/${note._id}`), user));
+
+			const followings = await Following.find({
+				followeeId: user._id,
+				'_follower.host': { $ne: null }
+			});
+
+			for (const following of followings) {
+				deliver(user, content, following._follower.inbox);
+			}
 		}
-	}
-	//#endregion
+		//#endregion
 
-	// 統計を更新
-	notesChart.update(note, false);
-	perUserNotesChart.update(user, note, false);
+		// 統計を更新
+		notesChart.update(note, false);
+		perUserNotesChart.update(user, note, false);
 
-	if (isRemoteUser(user)) {
-		registerOrFetchInstanceDoc(user.host).then(i => {
-			Instance.update({ _id: i._id }, {
-				$inc: {
-					notesCount: -1
-				}
-			});
+		if (isRemoteUser(user)) {
+			registerOrFetchInstanceDoc(user.host).then(i => {
+				Instance.update({ _id: i._id }, {
+					$inc: {
+						notesCount: -1
+					}
+				});
 
-			instanceChart.updateNote(i.host, false);
-		});
+				instanceChart.updateNote(i.host, false);
+			});
+		}
 	}
 }