Index: src/wp-includes/user.php
===================================================================
--- src/wp-includes/user.php	(revision 31321)
+++ src/wp-includes/user.php	(working copy)
@@ -631,6 +631,8 @@
 				$orderby = 'ID';
 			} elseif ( 'meta_value' == $qv['orderby'] ) {
 				$orderby = "$wpdb->usermeta.meta_value";
+			} elseif ( 'meta_value_num' == $qv['orderby'] ) {
+				$orderby = "$wpdb->usermeta.meta_value+0";
 			} elseif ( 'include' === $qv['orderby'] && ! empty( $include ) ) {
 				// Sanitized earlier.
 				$include_sql = implode( ',', $include );
Index: tests/phpunit/tests/user/query.php
===================================================================
--- tests/phpunit/tests/user/query.php	(revision 31268)
+++ tests/phpunit/tests/user/query.php	(working copy)
@@ -186,6 +186,30 @@
 	}
 
 	/**
+	 * @ticket 31220
+	 */
+	public function test_orderby_meta_value_num() {
+		$users = $this->factory->user->create_many( 3, array(
+			'role' => 'author'
+		) );
+
+		update_user_meta( $users[0], 'user_age', '101' );
+		update_user_meta( $users[1], 'user_age', '20' );
+		update_user_meta( $users[2], 'user_age', '25' );
+
+		$q = new WP_User_Query( array(
+			'include' => $users,
+			'meta_key' => 'user_age',
+			'orderby' => 'meta_value_num',
+			'fields' => 'ids'
+		) );
+
+		$expected = array( $users[1], $users[2], $users[0] );
+
+		$this->assertEquals( $expected, $q->get_results() );
+	}
+
+	/**
 	 * @ticket 21119
 	 */
 	function test_prepare_query() {
