diff --git a/CHANGELOG.md b/CHANGELOG.md
index a5db9bc963322d7d04412c059ed712869382a08c..d19545c7d9e6422697bc08a4e20af0af7f1c6742 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -99,6 +99,7 @@ You should also include the user name that made the change.
 - Server: アンテナの作成数上限を追加 @syuilo
 - Server: pages/likeのエラーIDが重複しているのを修正 @syuilo
 - Server: pages/updateのパラメータによってはsummaryの値が更新されないのを修正 @syuilo
+- Server: Escape SQL LIKE @mei23
 - Client: case insensitive emoji search @saschanaz
 - Client: InAppウィンドウが操作できなくなることがあるのを修正 @tamaina
 - Client: use proxied image for instance icon @syuilo
diff --git a/packages/backend/src/misc/sql-like-escape.ts b/packages/backend/src/misc/sql-like-escape.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8470dca3de39895c5a398257fa7401917b1fe6ae
--- /dev/null
+++ b/packages/backend/src/misc/sql-like-escape.ts
@@ -0,0 +1,3 @@
+export function sqlLikeEscape(s: string) {
+	return s.replace(/([%_])/g, '\\$1');
+}
diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts b/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts
index c03d27878c2ca80cbd43f7a1683e052bc838aa50..ed60efd7b4b9d86c916cef33d1d66286d03404e2 100644
--- a/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts
+++ b/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts
@@ -5,6 +5,7 @@ import { QueryService } from '@/core/QueryService.js';
 import { UtilityService } from '@/core/UtilityService.js';
 import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js';
 import { DI } from '@/di-symbols.js';
+import { sqlLikeEscape } from '@/misc/sql-like-escape';
 
 export const meta = {
 	tags: ['admin'],
@@ -92,7 +93,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 			}
 
 			if (ps.query) {
-				q.andWhere('emoji.name like :query', { query: '%' + ps.query + '%' });
+				q.andWhere('emoji.name like :query', { query: '%' + sqlLikeEscape(ps.query) + '%' });
 			}
 
 			const emojis = await q
diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/list.ts b/packages/backend/src/server/api/endpoints/admin/emoji/list.ts
index 271b142126285c53e93ea1476bf718273a22e49f..f357e45a527f66a0f1db32e1a43e65573868f715 100644
--- a/packages/backend/src/server/api/endpoints/admin/emoji/list.ts
+++ b/packages/backend/src/server/api/endpoints/admin/emoji/list.ts
@@ -5,6 +5,7 @@ import type { Emoji } from '@/models/entities/Emoji.js';
 import { QueryService } from '@/core/QueryService.js';
 import { DI } from '@/di-symbols.js';
 import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js';
+//import { sqlLikeEscape } from '@/misc/sql-like-escape';
 
 export const meta = {
 	tags: ['admin'],
@@ -82,7 +83,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 			let emojis: Emoji[];
 
 			if (ps.query) {
-				//q.andWhere('emoji.name ILIKE :q', { q: `%${ps.query}%` });
+				//q.andWhere('emoji.name ILIKE :q', { q: `%${ sqlLikeEscape(ps.query) }%` });
 				//const emojis = await q.take(ps.limit).getMany();
 
 				emojis = await q.getMany();
diff --git a/packages/backend/src/server/api/endpoints/admin/show-users.ts b/packages/backend/src/server/api/endpoints/admin/show-users.ts
index 33e1be804160e703b3407fa5759c764d350669d8..722e284dde63c9298b1a01f2018f91ed617a9c84 100644
--- a/packages/backend/src/server/api/endpoints/admin/show-users.ts
+++ b/packages/backend/src/server/api/endpoints/admin/show-users.ts
@@ -3,6 +3,7 @@ import type { UsersRepository } from '@/models/index.js';
 import { Endpoint } from '@/server/api/endpoint-base.js';
 import { DI } from '@/di-symbols.js';
 import { UserEntityService } from '@/core/entities/UserEntityService.js';
+import { sqlLikeEscape } from '@/misc/sql-like-escape';
 
 export const meta = {
 	tags: ['admin'],
@@ -68,7 +69,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 			}
 
 			if (ps.username) {
-				query.andWhere('user.usernameLower like :username', { username: ps.username.toLowerCase() + '%' });
+				query.andWhere('user.usernameLower like :username', { username: sqlLikeEscape(ps.username.toLowerCase()) + '%' });
 			}
 
 			if (ps.hostname) {
diff --git a/packages/backend/src/server/api/endpoints/federation/instances.ts b/packages/backend/src/server/api/endpoints/federation/instances.ts
index 5e2f2046612737f7ab1a2e9fec56849f8dbd1618..726979309fd8a64764ee5e5fe89d33b66bee0cb6 100644
--- a/packages/backend/src/server/api/endpoints/federation/instances.ts
+++ b/packages/backend/src/server/api/endpoints/federation/instances.ts
@@ -4,6 +4,7 @@ import type { InstancesRepository } from '@/models/index.js';
 import { InstanceEntityService } from '@/core/entities/InstanceEntityService.js';
 import { MetaService } from '@/core/MetaService.js';
 import { DI } from '@/di-symbols.js';
+import { sqlLikeEscape } from '@/misc/sql-like-escape';
 
 export const meta = {
 	tags: ['federation'],
@@ -120,7 +121,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 			}
 
 			if (ps.host) {
-				query.andWhere('instance.host like :host', { host: '%' + ps.host.toLowerCase() + '%' });
+				query.andWhere('instance.host like :host', { host: '%' + sqlLikeEscape(ps.host.toLowerCase()) + '%' });
 			}
 
 			const instances = await query.take(ps.limit).skip(ps.offset).getMany();
diff --git a/packages/backend/src/server/api/endpoints/hashtags/search.ts b/packages/backend/src/server/api/endpoints/hashtags/search.ts
index 7f787ea38fb2e9bbddeb3626087cfb05aa8beb50..6c56ef5da20ddc25cbbaed20bf7112ac5fb5e4b3 100644
--- a/packages/backend/src/server/api/endpoints/hashtags/search.ts
+++ b/packages/backend/src/server/api/endpoints/hashtags/search.ts
@@ -2,6 +2,7 @@ import { Inject, Injectable } from '@nestjs/common';
 import { Endpoint } from '@/server/api/endpoint-base.js';
 import type { HashtagsRepository } from '@/models/index.js';
 import { DI } from '@/di-symbols.js';
+import { sqlLikeEscape } from '@/misc/sql-like-escape';
 
 export const meta = {
 	tags: ['hashtags'],
@@ -37,7 +38,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 	) {
 		super(meta, paramDef, async (ps, me) => {
 			const hashtags = await this.hashtagsRepository.createQueryBuilder('tag')
-				.where('tag.name like :q', { q: ps.query.toLowerCase() + '%' })
+				.where('tag.name like :q', { q: sqlLikeEscape(ps.query.toLowerCase()) + '%' })
 				.orderBy('tag.count', 'DESC')
 				.groupBy('tag.id')
 				.take(ps.limit)
diff --git a/packages/backend/src/server/api/endpoints/notes/search.ts b/packages/backend/src/server/api/endpoints/notes/search.ts
index 27b477e14192d40b981eb02c61e9d1560658837b..02701ffe1e96ff9ecb05a131f630599c34750eb3 100644
--- a/packages/backend/src/server/api/endpoints/notes/search.ts
+++ b/packages/backend/src/server/api/endpoints/notes/search.ts
@@ -6,6 +6,7 @@ import { QueryService } from '@/core/QueryService.js';
 import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
 import type { Config } from '@/config.js';
 import { DI } from '@/di-symbols.js';
+import { sqlLikeEscape } from '@/misc/sql-like-escape';
 
 export const meta = {
 	tags: ['notes'],
@@ -70,7 +71,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 			}
 
 			query
-				.andWhere('note.text ILIKE :q', { q: `%${ps.query}%` })
+				.andWhere('note.text ILIKE :q', { q: `%${ sqlLikeEscape(ps.query) }%` })
 				.innerJoinAndSelect('note.user', 'user')
 				.leftJoinAndSelect('user.avatar', 'avatar')
 				.leftJoinAndSelect('user.banner', 'banner')
diff --git a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts
index f13df3ee9d095afef403ff77cda53bfde6ef7b3e..029b1e91c3251d47af3aad83d63e02adae341095 100644
--- a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts
+++ b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts
@@ -6,6 +6,7 @@ import type { User } from '@/models/entities/User.js';
 import { Endpoint } from '@/server/api/endpoint-base.js';
 import { UserEntityService } from '@/core/entities/UserEntityService.js';
 import { DI } from '@/di-symbols.js';
+import { sqlLikeEscape } from '@/misc/sql-like-escape';
 
 export const meta = {
 	tags: ['users'],
@@ -59,10 +60,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 			if (ps.host) {
 				const q = this.usersRepository.createQueryBuilder('user')
 					.where('user.isSuspended = FALSE')
-					.andWhere('user.host LIKE :host', { host: ps.host.toLowerCase() + '%' });
+					.andWhere('user.host LIKE :host', { host: sqlLikeEscape(ps.host.toLowerCase()) + '%' });
 
 				if (ps.username) {
-					q.andWhere('user.usernameLower LIKE :username', { username: ps.username.toLowerCase() + '%' });
+					q.andWhere('user.usernameLower LIKE :username', { username: sqlLikeEscape(ps.username.toLowerCase()) + '%' });
 				}
 
 				q.andWhere('user.updatedAt IS NOT NULL');
@@ -83,7 +84,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 						.where(`user.id IN (${ followingQuery.getQuery() })`)
 						.andWhere('user.id != :meId', { meId: me.id })
 						.andWhere('user.isSuspended = FALSE')
-						.andWhere('user.usernameLower LIKE :username', { username: ps.username.toLowerCase() + '%' })
+						.andWhere('user.usernameLower LIKE :username', { username: sqlLikeEscape(ps.username.toLowerCase()) + '%' })
 						.andWhere(new Brackets(qb => { qb
 							.where('user.updatedAt IS NULL')
 							.orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold });
@@ -101,7 +102,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 							.where(`user.id NOT IN (${ followingQuery.getQuery() })`)
 							.andWhere('user.id != :meId', { meId: me.id })
 							.andWhere('user.isSuspended = FALSE')
-							.andWhere('user.usernameLower LIKE :username', { username: ps.username.toLowerCase() + '%' })
+							.andWhere('user.usernameLower LIKE :username', { username: sqlLikeEscape(ps.username.toLowerCase()) + '%' })
 							.andWhere('user.updatedAt IS NOT NULL');
 
 						otherQuery.setParameters(followingQuery.getParameters());
@@ -116,7 +117,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 				} else {
 					users = await this.usersRepository.createQueryBuilder('user')
 						.where('user.isSuspended = FALSE')
-						.andWhere('user.usernameLower LIKE :username', { username: ps.username.toLowerCase() + '%' })
+						.andWhere('user.usernameLower LIKE :username', { username: sqlLikeEscape(ps.username.toLowerCase()) + '%' })
 						.andWhere('user.updatedAt IS NOT NULL')
 						.orderBy('user.updatedAt', 'DESC')
 						.take(ps.limit - users.length)
diff --git a/packages/backend/src/server/api/endpoints/users/search.ts b/packages/backend/src/server/api/endpoints/users/search.ts
index ba07714972d87135fedb4401c354bb0ac7b9ef69..25bd62126908bc2ac266494a28be82139af7917a 100644
--- a/packages/backend/src/server/api/endpoints/users/search.ts
+++ b/packages/backend/src/server/api/endpoints/users/search.ts
@@ -5,6 +5,7 @@ import type { User } from '@/models/entities/User.js';
 import { Endpoint } from '@/server/api/endpoint-base.js';
 import { UserEntityService } from '@/core/entities/UserEntityService.js';
 import { DI } from '@/di-symbols.js';
+import { sqlLikeEscape } from '@/misc/sql-like-escape';
 
 export const meta = {
 	tags: ['users'],
@@ -57,7 +58,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 
 			if (isUsername) {
 				const usernameQuery = this.usersRepository.createQueryBuilder('user')
-					.where('user.usernameLower LIKE :username', { username: ps.query.replace('@', '').toLowerCase() + '%' })
+					.where('user.usernameLower LIKE :username', { username: sqlLikeEscape(ps.query.replace('@', '').toLowerCase()) + '%' })
 					.andWhere(new Brackets(qb => { qb
 						.where('user.updatedAt IS NULL')
 						.orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold });
@@ -78,11 +79,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 			} else {
 				const nameQuery = this.usersRepository.createQueryBuilder('user')
 					.where(new Brackets(qb => { 
-						qb.where('user.name ILIKE :query', { query: '%' + ps.query + '%' });
+						qb.where('user.name ILIKE :query', { query: '%' + sqlLikeEscape(ps.query) + '%' });
 
 						// Also search username if it qualifies as username
 						if (this.userEntityService.validateLocalUsername(ps.query)) {
-							qb.orWhere('user.usernameLower LIKE :username', { username: '%' + ps.query.toLowerCase() + '%' });
+							qb.orWhere('user.usernameLower LIKE :username', { username: '%' + sqlLikeEscape(ps.query.toLowerCase()) + '%' });
 						}
 					}))
 					.andWhere(new Brackets(qb => { qb
@@ -106,7 +107,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 				if (users.length < ps.limit) {
 					const profQuery = this.userProfilesRepository.createQueryBuilder('prof')
 						.select('prof.userId')
-						.where('prof.description ILIKE :query', { query: '%' + ps.query + '%' });
+						.where('prof.description ILIKE :query', { query: '%' + sqlLikeEscape(ps.query) + '%' });
 
 					if (ps.origin === 'local') {
 						profQuery.andWhere('prof.userHost IS NULL');