diff --git a/app/Auth/User.php b/app/Auth/User.php
index 07232e1cc..9855ab4e7 100644
--- a/app/Auth/User.php
+++ b/app/Auth/User.php
@@ -1,6 +1,7 @@
 <?php namespace BookStack\Auth;
 
 use BookStack\Api\ApiToken;
+use BookStack\Entities\Tools\SlugGenerator;
 use BookStack\Interfaces\Loggable;
 use BookStack\Interfaces\Sluggable;
 use BookStack\Model;
@@ -266,7 +267,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
      */
     public function getProfileUrl(): string
     {
-        return url('/user/' . $this->id);
+        return url('/user/' . $this->slug);
     }
 
     /**
@@ -303,4 +304,13 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
     {
         return "({$this->id}) {$this->name}";
     }
+
+    /**
+     * @inheritDoc
+     */
+    public function refreshSlug(): string
+    {
+        $this->slug = app(SlugGenerator::class)->generate($this);
+        return $this->slug;
+    }
 }
diff --git a/app/Auth/UserRepo.php b/app/Auth/UserRepo.php
index 29a0ebc14..bcaf9cd09 100644
--- a/app/Auth/UserRepo.php
+++ b/app/Auth/UserRepo.php
@@ -45,6 +45,14 @@ class UserRepo
         return User::query()->findOrFail($id);
     }
 
+    /**
+     * Get a user by their slug.
+     */
+    public function getBySlug(string $slug): User
+    {
+        return User::query()->where('slug', '=', $slug)->firstOrFail();
+    }
+
     /**
      * Get all the users with their permissions.
      */
diff --git a/app/Entities/Models/Entity.php b/app/Entities/Models/Entity.php
index f5f43fe8c..d4b477304 100644
--- a/app/Entities/Models/Entity.php
+++ b/app/Entities/Models/Entity.php
@@ -290,11 +290,11 @@ abstract class Entity extends Model implements Sluggable
     }
 
     /**
-     * Generate and set a new URL slug for this model.
+     * @inheritdoc
      */
     public function refreshSlug(): string
     {
-        $this->slug = (new SlugGenerator)->generate($this);
+        $this->slug = app(SlugGenerator::class)->generate($this);
         return $this->slug;
     }
 }
diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php
index 92e1cd8b7..d797552f1 100644
--- a/app/Http/Controllers/UserController.php
+++ b/app/Http/Controllers/UserController.php
@@ -5,10 +5,13 @@ use BookStack\Auth\Access\SocialAuthService;
 use BookStack\Auth\Access\UserInviteService;
 use BookStack\Auth\User;
 use BookStack\Auth\UserRepo;
+use BookStack\Exceptions\ImageUploadException;
 use BookStack\Exceptions\UserUpdateException;
 use BookStack\Uploads\ImageRepo;
+use Exception;
 use Illuminate\Http\Request;
 use Illuminate\Support\Str;
+use Illuminate\Validation\ValidationException;
 
 class UserController extends Controller
 {
@@ -61,7 +64,7 @@ class UserController extends Controller
     /**
      * Store a newly created user in storage.
      * @throws UserUpdateException
-     * @throws \Illuminate\Validation\ValidationException
+     * @throws ValidationException
      */
     public function store(Request $request)
     {
@@ -90,6 +93,7 @@ class UserController extends Controller
             $user->external_auth_id = $request->get('external_auth_id');
         }
 
+        $user->refreshSlug();
         $user->save();
 
         if ($sendInvite) {
@@ -132,8 +136,8 @@ class UserController extends Controller
     /**
      * Update the specified user in storage.
      * @throws UserUpdateException
-     * @throws \BookStack\Exceptions\ImageUploadException
-     * @throws \Illuminate\Validation\ValidationException
+     * @throws ImageUploadException
+     * @throws ValidationException
      */
     public function update(Request $request, int $id)
     {
@@ -157,6 +161,11 @@ class UserController extends Controller
             $user->email = $request->get('email');
         }
 
+        // Refresh the slug if the user's name has changed
+        if ($user->isDirty('name')) {
+            $user->refreshSlug();
+        }
+
         // Role updates
         if (userCan('users-manage') && $request->filled('roles')) {
             $roles = $request->get('roles');
@@ -216,7 +225,7 @@ class UserController extends Controller
 
     /**
      * Remove the specified user from storage.
-     * @throws \Exception
+     * @throws Exception
      */
     public function destroy(Request $request, int $id)
     {
@@ -243,25 +252,6 @@ class UserController extends Controller
         return redirect('/settings/users');
     }
 
-    /**
-     * Show the user profile page
-     */
-    public function showProfilePage($id)
-    {
-        $user = $this->userRepo->getById($id);
-
-        $userActivity = $this->userRepo->getActivity($user);
-        $recentlyCreated = $this->userRepo->getRecentlyCreated($user, 5);
-        $assetCounts = $this->userRepo->getAssetCounts($user);
-
-        return view('users.profile', [
-            'user' => $user,
-            'activity' => $userActivity,
-            'recentlyCreated' => $recentlyCreated,
-            'assetCounts' => $assetCounts
-        ]);
-    }
-
     /**
      * Update the user's preferred book-list display setting.
      */
diff --git a/app/Http/Controllers/UserProfileController.php b/app/Http/Controllers/UserProfileController.php
new file mode 100644
index 000000000..95e68cb07
--- /dev/null
+++ b/app/Http/Controllers/UserProfileController.php
@@ -0,0 +1,25 @@
+<?php namespace BookStack\Http\Controllers;
+
+use BookStack\Auth\UserRepo;
+
+class UserProfileController extends Controller
+{
+    /**
+     * Show the user profile page
+     */
+    public function show(UserRepo $repo, string $slug)
+    {
+        $user = $repo->getBySlug($slug);
+
+        $userActivity = $repo->getActivity($user);
+        $recentlyCreated = $repo->getRecentlyCreated($user, 5);
+        $assetCounts = $repo->getAssetCounts($user);
+
+        return view('users.profile', [
+            'user' => $user,
+            'activity' => $userActivity,
+            'recentlyCreated' => $recentlyCreated,
+            'assetCounts' => $assetCounts
+        ]);
+    }
+}
diff --git a/app/Interfaces/Sluggable.php b/app/Interfaces/Sluggable.php
index 84f0e5bcd..6aa94e69c 100644
--- a/app/Interfaces/Sluggable.php
+++ b/app/Interfaces/Sluggable.php
@@ -15,4 +15,9 @@ use Illuminate\Database\Eloquent\Builder;
 interface Sluggable
 {
 
+    /**
+     * Regenerate the slug for this model.
+     */
+    public function refreshSlug(): string;
+
 }
\ No newline at end of file
diff --git a/resources/views/common/header.blade.php b/resources/views/common/header.blade.php
index 43ac273ef..52f6b8cbb 100644
--- a/resources/views/common/header.blade.php
+++ b/resources/views/common/header.blade.php
@@ -58,10 +58,10 @@
                         </span>
                         <ul refs="dropdown@menu" class="dropdown-menu" role="menu">
                             <li>
-                                <a href="{{ url("/user/{$currentUser->id}") }}">@icon('user'){{ trans('common.view_profile') }}</a>
+                                <a href="{{ $currentUser->getProfileUrl() }}">@icon('user'){{ trans('common.view_profile') }}</a>
                             </li>
                             <li>
-                                <a href="{{ url("/settings/users/{$currentUser->id}") }}">@icon('edit'){{ trans('common.edit_profile') }}</a>
+                                <a href="{{ $currentUser->getEditUrl() }}">@icon('edit'){{ trans('common.edit_profile') }}</a>
                             </li>
                             <li>
                                 @if(config('auth.method') === 'saml2')
diff --git a/routes/web.php b/routes/web.php
index 64d08e165..bb772b3dd 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -99,7 +99,7 @@ Route::group(['middleware' => 'auth'], function () {
     });
 
     // User Profile routes
-    Route::get('/user/{userId}', 'UserController@showProfilePage');
+    Route::get('/user/{slug}', 'UserProfileController@show');
 
     // Image routes
     Route::get('/images/gallery', 'Images\GalleryImageController@list');