diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index f8e068fe1970..401692388e5d 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -2823,6 +2823,7 @@ users.list_status_filter.is_prohibit_login = Prohibit Login
 users.list_status_filter.not_prohibit_login = Allow Login
 users.list_status_filter.is_2fa_enabled = 2FA Enabled
 users.list_status_filter.not_2fa_enabled = 2FA Disabled
+users.details = User Details
 
 emails.email_manage_panel = User Email Management
 emails.primary = Primary
diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go
index e560a88b4cff..61df49b85ba1 100644
--- a/routers/web/admin/users.go
+++ b/routers/web/admin/users.go
@@ -13,6 +13,8 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/models/auth"
 	"code.gitea.io/gitea/models/db"
+	org_model "code.gitea.io/gitea/models/organization"
+	repo_model "code.gitea.io/gitea/models/repo"
 	system_model "code.gitea.io/gitea/models/system"
 	user_model "code.gitea.io/gitea/models/user"
 	"code.gitea.io/gitea/modules/auth/password"
@@ -32,6 +34,7 @@ import (
 const (
 	tplUsers    base.TplName = "admin/user/list"
 	tplUserNew  base.TplName = "admin/user/new"
+	tplUserView base.TplName = "admin/user/view"
 	tplUserEdit base.TplName = "admin/user/edit"
 )
 
@@ -249,6 +252,61 @@ func prepareUserInfo(ctx *context.Context) *user_model.User {
 	return u
 }
 
+func ViewUser(ctx *context.Context) {
+	ctx.Data["Title"] = ctx.Tr("admin.users.details")
+	ctx.Data["PageIsAdminUsers"] = true
+	ctx.Data["DisableRegularOrgCreation"] = setting.Admin.DisableRegularOrgCreation
+	ctx.Data["DisableMigrations"] = setting.Repository.DisableMigrations
+	ctx.Data["AllowedUserVisibilityModes"] = setting.Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice()
+
+	u := prepareUserInfo(ctx)
+	if ctx.Written() {
+		return
+	}
+
+	repos, count, err := repo_model.SearchRepository(ctx, &repo_model.SearchRepoOptions{
+		ListOptions: db.ListOptions{
+			ListAll: true,
+		},
+		OwnerID:     u.ID,
+		OrderBy:     db.SearchOrderByAlphabetically,
+		Private:     true,
+		Collaborate: util.OptionalBoolFalse,
+	})
+	if err != nil {
+		ctx.ServerError("SearchRepository", err)
+		return
+	}
+
+	ctx.Data["Repos"] = repos
+	ctx.Data["ReposTotal"] = int(count)
+
+	emails, err := user_model.GetEmailAddresses(ctx.Doer.ID)
+	if err != nil {
+		ctx.ServerError("GetEmailAddresses", err)
+		return
+	}
+	ctx.Data["Emails"] = emails
+	ctx.Data["EmailsTotal"] = len(emails)
+
+	orgs, err := org_model.FindOrgs(org_model.FindOrgOptions{
+		ListOptions: db.ListOptions{
+			ListAll: true,
+		},
+		UserID:         u.ID,
+		IncludePrivate: true,
+	})
+	if err != nil {
+		ctx.ServerError("FindOrgs", err)
+		return
+	}
+
+	ctx.Data["Users"] = orgs // needed to be able to use explore/user_list template
+	ctx.Data["OrgsTotal"] = len(orgs)
+
+	ctx.HTML(http.StatusOK, tplUserView)
+}
+
 // EditUser show editing user page
 func EditUser(ctx *context.Context) {
 	ctx.Data["Title"] = ctx.Tr("admin.users.edit_account")
diff --git a/routers/web/web.go b/routers/web/web.go
index bbab9b37b597..ec6742f6ce76 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -573,7 +573,8 @@ func registerRoutes(m *web.Route) {
 		m.Group("/users", func() {
 			m.Get("", admin.Users)
 			m.Combo("/new").Get(admin.NewUser).Post(web.Bind(forms.AdminCreateUserForm{}), admin.NewUserPost)
-			m.Combo("/{userid}").Get(admin.EditUser).Post(web.Bind(forms.AdminEditUserForm{}), admin.EditUserPost)
+			m.Get("/{userid}", admin.ViewUser)
+			m.Combo("/{userid}/edit").Get(admin.EditUser).Post(web.Bind(forms.AdminEditUserForm{}), admin.EditUserPost)
 			m.Post("/{userid}/delete", admin.DeleteUser)
 			m.Post("/{userid}/avatar", web.Bind(forms.AvatarForm{}), admin.AvatarPost)
 			m.Post("/{userid}/avatar/delete", admin.DeleteAvatar)
diff --git a/templates/admin/layout_head.tmpl b/templates/admin/layout_head.tmpl
index 64d03d9e5488..0067f336e05c 100644
--- a/templates/admin/layout_head.tmpl
+++ b/templates/admin/layout_head.tmpl
@@ -1,6 +1,6 @@
 {{template "base/head" .ctxData}}
 <div role="main" aria-label="{{.ctxData.Title}}" class="page-content {{.pageClass}}">
-	<div class="ui container">
+	<div class="ui container gt-mb-4">
 		{{template "base/alert" .ctxData}}
 	</div>
 	<div class="ui container flex-container">
diff --git a/templates/admin/user/list.tmpl b/templates/admin/user/list.tmpl
index 45fed87a4001..b3e0caa16915 100644
--- a/templates/admin/user/list.tmpl
+++ b/templates/admin/user/list.tmpl
@@ -68,36 +68,35 @@
 						</th>
 						<th>{{.locale.Tr "email"}}</th>
 						<th>{{.locale.Tr "admin.users.activated"}}</th>
-						<th>{{.locale.Tr "admin.users.admin"}}</th>
 						<th>{{.locale.Tr "admin.users.restricted"}}</th>
 						<th>{{.locale.Tr "admin.users.2fa"}}</th>
-						<th>{{.locale.Tr "admin.users.repos"}}</th>
 						<th>{{.locale.Tr "admin.users.created"}}</th>
 						<th data-sortt-asc="lastlogin" data-sortt-desc="reverselastlogin">
 							{{.locale.Tr "admin.users.last_login"}}
 							{{SortArrow "lastlogin" "reverselastlogin" $.SortType false}}
 						</th>
-						<th>{{.locale.Tr "admin.users.edit"}}</th>
 					</tr>
 				</thead>
 				<tbody>
 					{{range .Users}}
 						<tr>
 							<td>{{.ID}}</td>
-							<td><a href="{{.HomeLink}}">{{.Name}}</a></td>
+							<td>
+								<a href="{{$.Link}}/{{.ID}}">{{.Name}}</a>
+								{{if .IsAdmin}}
+									<span class="ui basic label">{{$.locale.Tr "admin.users.admin"}}</span>
+								{{end}}
+							</td>
 							<td class="gt-ellipsis gt-max-width-12rem">{{.Email}}</td>
 							<td>{{if .IsActive}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</td>
-							<td>{{if .IsAdmin}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</td>
 							<td>{{if .IsRestricted}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</td>
 							<td>{{if index $.UsersTwoFaStatus .ID}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</td>
-							<td>{{.NumRepos}}</td>
 							<td>{{DateTime "short" .CreatedUnix}}</td>
 							{{if .LastLoginUnix}}
 								<td>{{DateTime "short" .LastLoginUnix}}</td>
 							{{else}}
 								<td><span>{{$.locale.Tr "admin.users.never_login"}}</span></td>
 							{{end}}
-							<td><a href="{{$.Link}}/{{.ID}}">{{svg "octicon-pencil"}}</a></td>
 						</tr>
 					{{end}}
 				</tbody>
diff --git a/templates/admin/user/view.tmpl b/templates/admin/user/view.tmpl
new file mode 100644
index 000000000000..fd3017607cdc
--- /dev/null
+++ b/templates/admin/user/view.tmpl
@@ -0,0 +1,48 @@
+{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin view user")}}
+
+<div class="admin-setting-content">
+	<div class="admin-responsive-columns">
+		<div class="gt-f1">
+			<h4 class="ui top attached header">
+				{{.Title}}
+				<div class="ui right">
+					<a class="ui primary tiny button" href="{{.Link}}/edit">{{ctx.Locale.Tr "admin.users.edit"}}</a>
+				</div>
+			</h4>
+			<div class="ui attached segment">
+				{{template "admin/user/view_details" .}}
+			</div>
+		</div>
+		<div class="gt-f1">
+			<h4 class="ui top attached header">
+				{{ctx.Locale.Tr "admin.emails"}}
+				<div class="ui right">
+					{{.EmailsTotal}}
+				</div>
+			</h4>
+			<div class="ui attached segment">
+				{{template "admin/user/view_emails" .}}
+			</div>
+		</div>
+	</div>
+	<h4 class="ui top attached header">
+		{{ctx.Locale.Tr "admin.repositories"}}
+		<div class="ui right">
+			{{.ReposTotal}}
+		</div>
+	</h4>
+	<div class="ui attached segment">
+		{{template "explore/repo_list" .}}
+	</div>
+	<h4 class="ui top attached header">
+		{{ctx.Locale.Tr "settings.organization"}}
+		<div class="ui right">
+			{{.OrgsTotal}}
+		</div>
+	</h4>
+	<div class="ui attached segment">
+		{{template "explore/user_list" .}}
+	</div>
+</div>
+
+{{template "admin/layout_footer" .}}
diff --git a/templates/admin/user/view_details.tmpl b/templates/admin/user/view_details.tmpl
new file mode 100644
index 000000000000..ceb3b9a05509
--- /dev/null
+++ b/templates/admin/user/view_details.tmpl
@@ -0,0 +1,65 @@
+<div class="flex-list">
+	<div class="flex-item">
+		<div class="flex-item-leading">
+			{{ctx.AvatarUtils.Avatar .User 48}}
+		</div>
+		<div class="flex-item-main">
+			<div class="flex-item-title">
+				{{template "shared/user/name" .User}}
+				{{if .User.IsAdmin}}
+					<span class="ui basic label">{{ctx.Locale.Tr "admin.users.admin"}}</span>
+				{{end}}
+			</div>
+			<div class="flex-item-body">
+				<b>{{ctx.Locale.Tr "admin.users.auth_source"}}:</b>
+				{{if eq .LoginSource.ID 0}}
+					{{ctx.Locale.Tr "admin.users.local"}}
+				{{else}}
+					{{.LoginSource.Name}}
+				{{end}}
+			</div>
+			<div class="flex-item-body">
+				<b>{{ctx.Locale.Tr "admin.users.activated"}}:</b>
+				{{if .User.IsActive}}
+					{{svg "octicon-check"}}
+				{{else}}
+					{{svg "octicon-x"}}
+				{{end}}
+			</div>
+			<div class="flex-item-body">
+				<b>{{ctx.Locale.Tr "admin.users.restricted"}}:</b>
+				{{if .User.IsRestricted}}
+					{{svg "octicon-check"}}
+				{{else}}
+					{{svg "octicon-x"}}
+				{{end}}
+			</div>
+			<div class="flex-item-body">
+				<b>{{ctx.Locale.Tr "settings.visibility"}}:</b>
+				{{if .User.Visibility.IsLimited}}{{ctx.Locale.Tr "settings.visibility.limited"}}{{end}}
+				{{if .User.Visibility.IsPrivate}}{{ctx.Locale.Tr "settings.visibility.private"}}{{end}}
+			</div>
+			<div class="flex-item-body">
+				<b>{{ctx.Locale.Tr "admin.users.2fa"}}:</b>
+				{{if .TwoFactorEnabled}}
+					<span class="text green">{{svg "octicon-check"}}</span>
+				{{else}}
+					{{svg "octicon-x"}}
+				{{end}}
+			</div>
+			{{if .User.Location}}
+				<div class="flex-item-body">
+					<span class="flex-text-inline">{{svg "octicon-location"}}{{.User.Location}}</span>
+				</div>
+			{{end}}
+			{{if .User.Website}}
+				<div class="flex-item-body">
+					<span class="flex-text-inline">
+						{{svg "octicon-link"}}
+						<a target="_blank" href="{{.User.Website}}">{{.User.Website}}</a>
+					</span>
+				</div>
+			{{end}}
+		</div>
+	</div>
+</div>
diff --git a/templates/admin/user/view_emails.tmpl b/templates/admin/user/view_emails.tmpl
new file mode 100644
index 000000000000..22ce305a88bc
--- /dev/null
+++ b/templates/admin/user/view_emails.tmpl
@@ -0,0 +1,19 @@
+<div class="flex-list">
+	{{range .Emails}}
+		<div class="flex-item">
+			<div class="flex-item-main">
+				<div class="flex-text-block">
+					{{.Email}}
+					{{if .IsPrimary}}
+						<div class="ui primary label">{{ctx.Locale.Tr "settings.primary"}}</div>
+					{{end}}
+					{{if .IsActivated}}
+						<div class="ui green label">{{ctx.Locale.Tr "settings.activated"}}</div>
+					{{else}}
+						<div class="ui label">{{ctx.Locale.Tr "settings.requires_activation"}}</div>
+					{{end}}
+				</div>
+			</div>
+		</div>
+	{{end}}
+</div>
diff --git a/templates/explore/user_list.tmpl b/templates/explore/user_list.tmpl
new file mode 100644
index 000000000000..cf6a2933b0fe
--- /dev/null
+++ b/templates/explore/user_list.tmpl
@@ -0,0 +1,31 @@
+<div class="flex-list">
+	{{range .Users}}
+		<div class="flex-item flex-item-center">
+			<div class="flex-item-leading">
+				{{ctx.AvatarUtils.Avatar . 48}}
+			</div>
+			<div class="flex-item-main">
+				<div class="flex-item-title">
+					{{template "shared/user/name" .}}
+					{{if .Visibility.IsPrivate}}
+						<span class="ui basic tiny label">{{ctx.Locale.Tr "repo.desc.private"}}</span>
+					{{end}}
+				</div>
+				<div class="flex-item-body">
+					{{if .Location}}
+						<span class="flex-text-inline">{{svg "octicon-location"}}{{.Location}}</span>
+					{{end}}
+					{{if and .Email (or (and $.ShowUserEmail $.IsSigned (not .KeepEmailPrivate)) $.PageIsAdminUsers)}}
+						<span class="flex-text-inline">
+							{{svg "octicon-mail"}}
+							<a href="mailto:{{.Email}}">{{.Email}}</a>
+						</span>
+					{{end}}
+					<span class="flex-text-inline">{{svg "octicon-calendar"}}{{ctx.Locale.Tr "user.joined_on" (DateTime "short" .CreatedUnix) | Safe}}</span>
+				</div>
+			</div>
+		</div>
+	{{else}}
+		<div class="flex-item">{{ctx.Locale.Tr "explore.user_no_results"}}</div>
+	{{end}}
+</div>
diff --git a/templates/explore/users.tmpl b/templates/explore/users.tmpl
index 1280f4add664..7e15ae3d47f4 100644
--- a/templates/explore/users.tmpl
+++ b/templates/explore/users.tmpl
@@ -4,37 +4,7 @@
 	<div class="ui container">
 		{{template "explore/search" .}}
 
-		<div class="flex-list">
-			{{range .Users}}
-				<div class="flex-item flex-item-center">
-					<div class="flex-item-leading">
-						{{ctx.AvatarUtils.Avatar . 48}}
-					</div>
-					<div class="flex-item-main">
-						<div class="flex-item-title">
-							{{template "shared/user/name" .}}
-							{{if .Visibility.IsPrivate}}
-								<span class="ui basic tiny label">{{$.locale.Tr "repo.desc.private"}}</span>
-							{{end}}
-						</div>
-						<div class="flex-item-body">
-							{{if .Location}}
-								<span class="flex-text-inline">{{svg "octicon-location"}}{{.Location}}</span>
-							{{end}}
-							{{if and $.ShowUserEmail .Email $.IsSigned (not .KeepEmailPrivate)}}
-								<span class="flex-text-inline">
-									{{svg "octicon-mail"}}
-									<a href="mailto:{{.Email}}" rel="nofollow">{{.Email}}</a>
-								</span>
-							{{end}}
-							<span class="flex-text-inline">{{svg "octicon-calendar"}}{{$.locale.Tr "user.joined_on" (DateTime "short" .CreatedUnix) | Safe}}</span>
-						</div>
-					</div>
-				</div>
-			{{else}}
-				<div class="flex-item">{{$.locale.Tr "explore.user_no_results"}}</div>
-			{{end}}
-		</div>
+		{{template "explore/user_list" .}}
 
 		{{template "base/paginate" .}}
 	</div>
diff --git a/tests/integration/admin_user_test.go b/tests/integration/admin_user_test.go
index dd6b9ccbbeb8..669060c787d4 100644
--- a/tests/integration/admin_user_test.go
+++ b/tests/integration/admin_user_test.go
@@ -51,8 +51,8 @@ func testSuccessfullEdit(t *testing.T, formData user_model.User) {
 
 func makeRequest(t *testing.T, formData user_model.User, headerCode int) {
 	session := loginUser(t, "user1")
-	csrf := GetCSRF(t, session, "/admin/users/"+strconv.Itoa(int(formData.ID)))
-	req := NewRequestWithValues(t, "POST", "/admin/users/"+strconv.Itoa(int(formData.ID)), map[string]string{
+	csrf := GetCSRF(t, session, "/admin/users/"+strconv.Itoa(int(formData.ID))+"/edit")
+	req := NewRequestWithValues(t, "POST", "/admin/users/"+strconv.Itoa(int(formData.ID))+"/edit", map[string]string{
 		"_csrf":      csrf,
 		"user_name":  formData.Name,
 		"login_name": formData.LoginName,
@@ -72,7 +72,7 @@ func TestAdminDeleteUser(t *testing.T) {
 
 	session := loginUser(t, "user1")
 
-	csrf := GetCSRF(t, session, "/admin/users/8")
+	csrf := GetCSRF(t, session, "/admin/users/8/edit")
 	req := NewRequestWithValues(t, "POST", "/admin/users/8/delete", map[string]string{
 		"_csrf": csrf,
 	})
diff --git a/web_src/css/admin.css b/web_src/css/admin.css
index fecae5f2bf98..e6866b27a688 100644
--- a/web_src/css/admin.css
+++ b/web_src/css/admin.css
@@ -42,3 +42,10 @@
 .admin .table th {
   white-space: nowrap;
 }
+
+.admin-responsive-columns {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 1rem;
+  margin-bottom: 1rem;
+}