diff --git a/app/assets/javascripts/admin/models/admin-user.js.es6 b/app/assets/javascripts/admin/models/admin-user.js.es6
index 267d951e5..14b7e3edc 100644
--- a/app/assets/javascripts/admin/models/admin-user.js.es6
+++ b/app/assets/javascripts/admin/models/admin-user.js.es6
@@ -402,7 +402,7 @@ const AdminUser = Discourse.User.extend({
           }
         }
       }).catch(function() {
-        AdminUser.find( user.get('username') ).then(function(u){ user.setProperties(u); });
+        AdminUser.find(user.get('id')).then(u => user.setProperties(u));
         bootbox.alert(I18n.t("admin.user.delete_failed"));
       });
     };
@@ -475,7 +475,7 @@ const AdminUser = Discourse.User.extend({
 
     if (user.get('loadedDetails')) { return Ember.RSVP.resolve(user); }
 
-    return AdminUser.find(user.get('username_lower')).then(function (result) {
+    return AdminUser.find(user.get('id')).then(result => {
       user.setProperties(result);
       user.set('loadedDetails', true);
     });
@@ -533,8 +533,8 @@ AdminUser.reopenClass({
     });
   },
 
-  find(username) {
-    return Discourse.ajax("/admin/users/" + username + ".json").then(function (result) {
+  find(user_id) {
+    return Discourse.ajax("/admin/users/" + user_id + ".json").then(result => {
       result.loadedDetails = true;
       return AdminUser.create(result);
     });
diff --git a/app/assets/javascripts/admin/routes/admin-route-map.js.es6 b/app/assets/javascripts/admin/routes/admin-route-map.js.es6
index 3626ea48d..64a8e393a 100644
--- a/app/assets/javascripts/admin/routes/admin-route-map.js.es6
+++ b/app/assets/javascripts/admin/routes/admin-route-map.js.es6
@@ -62,7 +62,7 @@ export default {
     });
 
     this.resource('adminUsers', { path: '/users' }, function() {
-      this.resource('adminUser', { path: '/:username' }, function() {
+      this.resource('adminUser', { path: '/:user_id/:username' }, function() {
         this.route('badges');
         this.route('tl3Requirements', { path: '/tl3_requirements' });
       });
diff --git a/app/assets/javascripts/admin/routes/admin-user.js.es6 b/app/assets/javascripts/admin/routes/admin-user.js.es6
index af3171a85..35a105a10 100644
--- a/app/assets/javascripts/admin/routes/admin-user.js.es6
+++ b/app/assets/javascripts/admin/routes/admin-user.js.es6
@@ -2,11 +2,11 @@ import AdminUser from 'admin/models/admin-user';
 
 export default Discourse.Route.extend({
   serialize(model) {
-    return { username: model.get('username').toLowerCase() };
+    return { user_id: model.get('id'), username: model.get('username').toLowerCase() };
   },
 
   model(params) {
-    return AdminUser.find(Em.get(params, 'username').toLowerCase());
+    return AdminUser.find(Em.get(params, 'user_id'));
   },
 
   renderTemplate() {
diff --git a/app/assets/javascripts/discourse/controllers/flag.js.es6 b/app/assets/javascripts/discourse/controllers/flag.js.es6
index 07db5951b..ea3bc834e 100644
--- a/app/assets/javascripts/discourse/controllers/flag.js.es6
+++ b/app/assets/javascripts/discourse/controllers/flag.js.es6
@@ -141,8 +141,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
   fetchUserDetails() {
     if (Discourse.User.currentProp('staff') && this.get('model.username')) {
       const AdminUser = require('admin/models/admin-user').default;
-      AdminUser.find(this.get('model.username').toLowerCase())
-                         .then(user => this.set('userDetails', user));
+      AdminUser.find(this.get('model.id')).then(user => this.set('userDetails', user));
     }
   }
 
diff --git a/app/assets/javascripts/discourse/controllers/user.js.es6 b/app/assets/javascripts/discourse/controllers/user.js.es6
index 3971558f8..64202d098 100644
--- a/app/assets/javascripts/discourse/controllers/user.js.es6
+++ b/app/assets/javascripts/discourse/controllers/user.js.es6
@@ -84,8 +84,7 @@ export default Ember.Controller.extend(CanCheckEmails, {
     adminDelete() {
       // I really want this deferred, don't want to bring in all this code till used
       const AdminUser = require('admin/models/admin-user').default;
-      AdminUser.find(this.get('model.username').toLowerCase())
-                         .then(user => user.destroy({deletePosts: true}));
+      AdminUser.find(this.get('model.id')).then(user => user.destroy({deletePosts: true}));
     },
 
   }
diff --git a/app/assets/javascripts/discourse/models/user.js.es6 b/app/assets/javascripts/discourse/models/user.js.es6
index 442899731..fd702adff 100644
--- a/app/assets/javascripts/discourse/models/user.js.es6
+++ b/app/assets/javascripts/discourse/models/user.js.es6
@@ -90,7 +90,7 @@ const User = RestModel.extend({
 
   },
 
-  adminPath: url('username_lower', "/admin/users/%@"),
+  adminPath: url('id', 'username_lower', "/admin/users/%@1/%@2"),
 
   mutedTopicsPath: url('/latest?state=muted'),
 
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index 36aa18f19..da18abe08 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -37,7 +37,7 @@ class Admin::UsersController < Admin::AdminController
   end
 
   def show
-    @user = User.find_by(username_lower: params[:id])
+    @user = User.find_by(id: params[:id])
     raise Discourse::NotFound unless @user
     render_serialized(@user, AdminDetailedUserSerializer, root: false)
   end
diff --git a/config/routes.rb b/config/routes.rb
index 49d7a623e..d0457c90c 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -73,8 +73,7 @@ Discourse::Application.routes.draw do
     get "groups/:type" => "groups#show", constraints: AdminConstraint.new
     get "groups/:type/:id" => "groups#show", constraints: AdminConstraint.new
 
-    get "users/:id.json" => 'users#show' , id: USERNAME_ROUTE_FORMAT, defaults: {format: 'json'}
-    resources :users, id: USERNAME_ROUTE_FORMAT do
+    resources :users, id: USERNAME_ROUTE_FORMAT, except: [:show] do
       collection do
         get "list/:query" => "users#index"
         get "ip-info" => "users#ip_info"
@@ -109,6 +108,8 @@ Discourse::Application.routes.draw do
       get "tl3_requirements"
       put "anonymize"
     end
+    get "users/:id.json" => 'users#show', defaults: {format: 'json'}
+    get 'users/:id/:username' => 'users#show'
 
 
     post "users/sync_sso" => "users#sync_sso", constraints: AdminConstraint.new
diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb
index c35c83d3c..b3de18096 100644
--- a/spec/controllers/admin/users_controller_spec.rb
+++ b/spec/controllers/admin/users_controller_spec.rb
@@ -47,14 +47,14 @@ describe Admin::UsersController do
     describe '.show' do
       context 'an existing user' do
         it 'returns success' do
-          xhr :get, :show, id: @user.username
+          xhr :get, :show, id: @user.id
           expect(response).to be_success
         end
       end
 
       context 'an existing user' do
         it 'returns success' do
-          xhr :get, :show, id: 'foobar'
+          xhr :get, :show, id: 0
           expect(response).not_to be_success
         end
       end