diff --git a/internal/db/org.go b/internal/db/org.go
index b0301c7b1..320dce3ab 100644
--- a/internal/db/org.go
+++ b/internal/db/org.go
@@ -8,23 +8,8 @@ import (
 	"fmt"
 
 	"xorm.io/builder"
-	"xorm.io/xorm"
 )
 
-// getOwnedOrgsByUserID returns a list of organizations are owned by given user ID.
-func getOwnedOrgsByUserID(sess *xorm.Session, userID int64) ([]*User, error) {
-	orgs := make([]*User, 0, 10)
-	return orgs, sess.Where("`org_user`.uid=?", userID).And("`org_user`.is_owner=?", true).
-		Join("INNER", "`org_user`", "`org_user`.org_id=`user`.id").Find(&orgs)
-}
-
-// GetOwnedOrganizationsByUserIDDesc returns a list of organizations are owned by
-// given user ID, ordered descending by the given condition.
-func GetOwnedOrgsByUserIDDesc(userID int64, desc string) ([]*User, error) {
-	sess := x.NewSession()
-	return getOwnedOrgsByUserID(sess.Desc(desc), userID)
-}
-
 // getOrgUsersByOrgID returns all organization-user relations by organization ID.
 func getOrgUsersByOrgID(e Engine, orgID int64, limit int) ([]*OrgUser, error) {
 	orgUsers := make([]*OrgUser, 0, 10)
diff --git a/internal/db/organizations.go b/internal/db/organizations.go
index d5a2f2add..8e3b36070 100644
--- a/internal/db/organizations.go
+++ b/internal/db/organizations.go
@@ -215,8 +215,15 @@ func (db *organizations) RemoveMember(ctx context.Context, orgID, userID int64)
 	})
 }
 
+type OrderBy int
+
+const (
+	OrderByIDAsc OrderBy = iota + 1
+	OrderByUpdatedDesc
+)
+
 type accessibleRepositoriesByUserOptions struct {
-	orderBy  string
+	orderBy  OrderBy
 	page     int
 	pageSize int
 }
@@ -249,8 +256,8 @@ func (*organizations) accessibleRepositoriesByUser(tx *gorm.DB, orgID, userID in
 			).
 			Or("repository.is_private = ? AND repository.is_unlisted = ?", false, false),
 		)
-	if opts.orderBy != "" {
-		conds.Order(opts.orderBy)
+	if opts.orderBy == OrderByUpdatedDesc {
+		conds.Order("updated_unix DESC")
 	}
 	if opts.page > 0 && opts.pageSize > 0 {
 		conds.Limit(opts.pageSize).Offset((opts.page - 1) * opts.pageSize)
@@ -269,7 +276,7 @@ func (db *organizations) AccessibleRepositoriesByUser(ctx context.Context, orgID
 		orgID,
 		userID,
 		accessibleRepositoriesByUserOptions{
-			orderBy:  "updated_unix DESC",
+			orderBy:  OrderByUpdatedDesc,
 			page:     page,
 			pageSize: pageSize,
 		},
@@ -339,10 +346,18 @@ func (db *organizations) ListMembers(ctx context.Context, orgID int64, opts List
 }
 
 type ListOrganizationsOptions struct {
-	// Filter by the membership with the given user ID.
+	// Filter by the membership with the given user ID. It cannot be set when the
+	// OwnerID is also set.
 	MemberID int64
+	// Filter by the ownership with the given user ID. It cannot be set when the
+	// MemberID is also set.
+	OwnerID int64
 	// Whether to include private memberships.
 	IncludePrivateMembers bool
+
+	// Order by the given field and direction. Default is OrderByIDAsc.
+	OrderBy OrderBy
+
 	// 1-based page number.
 	Page int
 	// Number of results per page.
@@ -350,8 +365,8 @@ type ListOrganizationsOptions struct {
 }
 
 func (db *organizations) List(ctx context.Context, opts ListOrganizationsOptions) ([]*Organization, error) {
-	if opts.MemberID <= 0 {
-		return nil, errors.New("MemberID must be greater than 0")
+	if opts.MemberID > 0 && opts.OwnerID > 0 {
+		return nil, errors.New("cannot filter by both MemberID and OwnerID")
 	}
 
 	/*
@@ -361,24 +376,32 @@ func (db *organizations) List(ctx context.Context, opts ListOrganizationsOptions
 		[JOIN org_user ON org_user.org_id = user.id]
 		WHERE
 			type = @type
-		[AND org_user.uid = @memberID
-		AND org_user.is_public = @includePrivateMembers]
-		ORDER BY user.id ASC
+		[AND org_user.uid = (@memberID | @ownerID)
+		AND org_user.is_public = @includePrivateMembers
+		AND org_user.is_owner = @ownerID > 0]
+		ORDER BY (user.id ASC | user.updated_unix DESC)
 		[LIMIT @limit OFFSET @offset]
 	*/
-	conds := db.WithContext(ctx).
-		Where("type = ?", UserTypeOrganization).
-		Order(dbutil.Quote("%s.id ASC", "user"))
+	conds := db.WithContext(ctx).Where("type = ?", UserTypeOrganization)
 
-	if opts.MemberID > 0 || !opts.IncludePrivateMembers {
+	if opts.MemberID > 0 || opts.OwnerID > 0 || !opts.IncludePrivateMembers {
 		conds.Joins(dbutil.Quote("JOIN org_user ON org_user.org_id = %s.id", "user"))
 	}
 	if opts.MemberID > 0 {
 		conds.Where("org_user.uid = ?", opts.MemberID)
+	} else if opts.OwnerID > 0 {
+		conds.Where("org_user.uid = ? AND org_user.is_owner = ?", opts.OwnerID, true)
 	}
 	if !opts.IncludePrivateMembers {
 		conds.Where("org_user.is_public = ?", true)
 	}
+
+	if opts.OrderBy == OrderByUpdatedDesc {
+		conds.Order(dbutil.Quote("%s.updated_unix DESC", "user"))
+	} else {
+		conds.Order(dbutil.Quote("%s.id ASC", "user"))
+	}
+
 	if opts.Page > 0 && opts.PageSize > 0 {
 		conds.Limit(opts.PageSize).Offset((opts.Page - 1) * opts.PageSize)
 	}
diff --git a/internal/route/repo/repo.go b/internal/route/repo/repo.go
index f19bd3dfb..5da0dfcbe 100644
--- a/internal/route/repo/repo.go
+++ b/internal/route/repo/repo.go
@@ -35,7 +35,13 @@ func MustBeNotBare(c *context.Context) {
 }
 
 func checkContextUser(c *context.Context, uid int64) *db.User {
-	orgs, err := db.GetOwnedOrgsByUserIDDesc(c.User.ID, "updated_unix")
+	orgs, err := db.Organizations.List(
+		c.Req.Context(),
+		db.ListOrganizationsOptions{
+			OwnerID: c.User.ID,
+			OrderBy: db.OrderByUpdatedDesc,
+		},
+	)
 	if err != nil {
 		c.Error(err, "get owned organization by user ID")
 		return nil