diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go
index 93a736630e..6d0511ec17 100644
--- a/models/migrations/migrations.go
+++ b/models/migrations/migrations.go
@@ -562,6 +562,8 @@ var migrations = []Migration{
 	NewMigration("Add support for SHA256 git repositories", v1_22.AdjustDBForSha256),
 	// v287 -> v288
 	NewMigration("Use Slug instead of ID for Badges", v1_22.UseSlugInsteadOfIDForBadges),
+	// v288 -> v289
+	NewMigration("Add user_blocking table", v1_22.AddUserBlockingTable),
 }
 
 // GetCurrentDBVersion returns the current db version
diff --git a/models/migrations/v1_22/v288.go b/models/migrations/v1_22/v288.go
new file mode 100644
index 0000000000..7c93bfcc66
--- /dev/null
+++ b/models/migrations/v1_22/v288.go
@@ -0,0 +1,26 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package v1_22 //nolint
+
+import (
+	"code.gitea.io/gitea/modules/timeutil"
+
+	"xorm.io/xorm"
+)
+
+type Blocking struct {
+	ID          int64 `xorm:"pk autoincr"`
+	BlockerID   int64 `xorm:"UNIQUE(block)"`
+	BlockeeID   int64 `xorm:"UNIQUE(block)"`
+	Note        string
+	CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
+}
+
+func (*Blocking) TableName() string {
+	return "user_blocking"
+}
+
+func AddUserBlockingTable(x *xorm.Engine) error {
+	return x.Sync(&Blocking{})
+}