Index: src/wp-admin/includes/user.php
===================================================================
--- src/wp-admin/includes/user.php	(revision 38287)
+++ src/wp-admin/includes/user.php	(working copy)
@@ -20,7 +20,7 @@
 /**
  * Edit user settings based on contents of $_POST
  *
- * Used on user-edit.php and profile.php to manage and process user options, passwords etc.
+ * Used on user-edit.php, user-new.php, and profile.php to manage and process user options, passwords etc.
  *
  * @since 2.0.0
  *
@@ -39,9 +39,6 @@
 		$update = false;
 	}
 
-	if ( !$update && isset( $_POST['user_login'] ) )
-		$user->user_login = sanitize_user($_POST['user_login'], true);
-
 	$pass1 = $pass2 = '';
 	if ( isset( $_POST['pass1'] ) )
 		$pass1 = $_POST['pass1'];
@@ -104,10 +101,17 @@
 
 	$errors = new WP_Error();
 
-	/* checking that username has been typed */
-	if ( $user->user_login == '' )
-		$errors->add( 'user_login', __( '<strong>ERROR</strong>: Please enter a username.' ) );
+	/* Validate the user_login when not updating the user */
+	if ( ! $update ) {
+		$user->user_login = '';
 
+		if ( isset( $_POST['user_login'] ) ) {
+			$user->user_login = $_POST['user_login'];
+		}
+
+		wp_validate_user_login( $user->user_login, $errors );
+	}
+
 	/* checking that nickname has been typed */
 	if ( $update && empty( $user->nickname ) ) {
 		$errors->add( 'nickname', __( '<strong>ERROR</strong>: Please enter a nickname.' ) );
@@ -142,12 +146,6 @@
 	if ( !empty( $pass1 ) )
 		$user->user_pass = $pass1;
 
-	if ( !$update && isset( $_POST['user_login'] ) && !validate_username( $_POST['user_login'] ) )
-		$errors->add( 'user_login', __( '<strong>ERROR</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.' ));
-
-	if ( !$update && username_exists( $user->user_login ) )
-		$errors->add( 'user_login', __( '<strong>ERROR</strong>: This username is already registered. Please choose another one.' ));
-
 	/** This filter is documented in wp-includes/user.php */
 	$illegal_logins = (array) apply_filters( 'illegal_user_logins', array() );
 
Index: src/wp-includes/ms-default-filters.php
===================================================================
--- src/wp-includes/ms-default-filters.php	(revision 38287)
+++ src/wp-includes/ms-default-filters.php	(working copy)
@@ -30,7 +30,6 @@
 add_action( 'network_site_new_created_user',   'wp_send_new_user_notifications' );
 add_action( 'network_site_users_created_user', 'wp_send_new_user_notifications' );
 add_action( 'network_user_new_created_user',   'wp_send_new_user_notifications' );
-add_filter( 'sanitize_user', 'strtolower' );
 
 // Blogs
 add_filter( 'wpmu_validate_blog_signup', 'signup_nonce_check' );
Index: wp-includes/ms-functions.php
===================================================================
--- src/wp-includes/ms-functions.php	(revision 38287)
+++ src/wp-includes/ms-functions.php	(working copy)
@@ -403,58 +403,22 @@
  *
  * @global wpdb $wpdb WordPress database abstraction object.
  *
- * @param string $user_name  The login name provided by the user.
+ * @param string $user_login The login name provided by the user.
  * @param string $user_email The email provided by the user.
  * @return array Contains username, email, and error messages.
  */
-function wpmu_validate_user_signup($user_name, $user_email) {
+function wpmu_validate_user_signup( $user_login, $user_email ) {
 	global $wpdb;
 
 	$errors = new WP_Error();
+	$orig_userlogin = $user_login;
+	wp_validate_user_login( $user_login, $errors );
 
-	$orig_username = $user_name;
-	$user_name = preg_replace( '/\s+/', '', sanitize_user( $user_name, true ) );
-
-	if ( $user_name != $orig_username || preg_match( '/[^a-z0-9]/', $user_name ) ) {
-		$errors->add( 'user_name', __( 'Usernames can only contain lowercase letters (a-z) and numbers.' ) );
-		$user_name = $orig_username;
-	}
-
 	$user_email = sanitize_email( $user_email );
 
-	if ( empty( $user_name ) )
-	   	$errors->add('user_name', __( 'Please enter a username.' ) );
-
-	$illegal_names = get_site_option( 'illegal_names' );
-	if ( ! is_array( $illegal_names ) ) {
-		$illegal_names = array(  'www', 'web', 'root', 'admin', 'main', 'invite', 'administrator' );
-		add_site_option( 'illegal_names', $illegal_names );
-	}
-	if ( in_array( $user_name, $illegal_names ) ) {
-		$errors->add( 'user_name',  __( 'Sorry, that username is not allowed.' ) );
-	}
-
-	/** This filter is documented in wp-includes/user.php */
-	$illegal_logins = (array) apply_filters( 'illegal_user_logins', array() );
-
-	if ( in_array( strtolower( $user_name ), array_map( 'strtolower', $illegal_logins ) ) ) {
-		$errors->add( 'user_name',  __( 'Sorry, that username is not allowed.' ) );
-	}
-
 	if ( is_email_address_unsafe( $user_email ) )
 		$errors->add('user_email',  __('You cannot use that email address to signup. We are having problems with them blocking some of our email. Please use another email provider.'));
 
-	if ( strlen( $user_name ) < 4 )
-		$errors->add('user_name',  __( 'Username must be at least 4 characters.' ) );
-
-	if ( strlen( $user_name ) > 60 ) {
-		$errors->add( 'user_name', __( 'Username may not be longer than 60 characters.' ) );
-	}
-
-	// all numeric?
-	if ( preg_match( '/^[0-9]*$/', $user_name ) )
-		$errors->add('user_name', __('Sorry, usernames must have letters too!'));
-
 	if ( !is_email( $user_email ) )
 		$errors->add('user_email', __( 'Please enter a valid email address.' ) );
 
@@ -466,27 +430,10 @@
 		}
 	}
 
-	// Check if the username has been used already.
-	if ( username_exists($user_name) )
-		$errors->add( 'user_name', __( 'Sorry, that username already exists!' ) );
-
 	// Check if the email address has been used already.
 	if ( email_exists($user_email) )
 		$errors->add( 'user_email', __( 'Sorry, that email address is already used!' ) );
 
-	// Has someone already signed up for this username?
-	$signup = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->signups WHERE user_login = %s", $user_name) );
-	if ( $signup != null ) {
-		$registered_at =  mysql2date('U', $signup->registered);
-		$now = current_time( 'timestamp', true );
-		$diff = $now - $registered_at;
-		// If registered more than two days ago, cancel registration and let this signup go through.
-		if ( $diff > 2 * DAY_IN_SECONDS )
-			$wpdb->delete( $wpdb->signups, array( 'user_login' => $user_name ) );
-		else
-			$errors->add('user_name', __('That username is currently reserved but may be available in a couple of days.'));
-	}
-
 	$signup = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->signups WHERE user_email = %s", $user_email) );
 	if ( $signup != null ) {
 		$diff = current_time( 'timestamp', true ) - mysql2date('U', $signup->registered);
@@ -497,7 +444,7 @@
 			$errors->add('user_email', __('That email address has already been used. Please check your inbox for an activation email. It will become available in a couple of days if you do nothing.'));
 	}
 
-	$result = array('user_name' => $user_name, 'orig_username' => $orig_username, 'user_email' => $user_email, 'errors' => $errors);
+	$result = array( 'user_name' => $user_login, 'orig_username' => $orig_userlogin, 'user_email' => $user_email, 'errors' => $errors );
 
 	/**
 	 * Filters the validated user registration details.
Index: src/wp-includes/user.php
===================================================================
--- src/wp-includes/user.php	(revision 38287)
+++ src/wp-includes/user.php	(working copy)
@@ -2229,6 +2229,132 @@
 }
 
 /**
+ * Validate a provided user_login
+ *
+ * user_login requirements:
+ *     - minimum of 4 characters
+ *     - maximum of 60 characters
+ *     - only contains (case-insensitive) characters: a-z 0-9 _ . - @
+ *     - no whitespace
+ *     - not on blacklist of illegal names
+ *     - contains at least one letter
+ *     - must be unique
+ *     - not pending signup already
+ *
+ * @since TBD
+ *
+ * @param string $user_login The user_login value to be be validated.
+ *
+ * @return True|WP_Error True if the user login is valid, WP_Error otherwise.
+ */
+function wp_validate_user_login( $user_login = '', $errors = null ) {
+	global $wpdb;
+	$original_user_login = $user_login;
+
+	if ( ! is_wp_error( $errors ) ) {
+		$errors = new WP_Error();
+	}
+
+	// User login cannot be empty
+	if ( empty( $user_login ) ) {
+		$errors->add( 'user_name', __( 'Please enter a username.' ) );
+	}
+
+	// User login must be less than 60 characters
+	if ( strlen( $user_login ) > 60 ) {
+		$errors->add( 'user_name', __( 'Username may not be longer than 60 characters.' ) );
+	}
+
+	// Check if the login passes sanitize_user() which doesn't strip whitespace
+	$user_login = sanitize_user( $user_login, true );
+
+	// If the previous operation generated a different value, the username is invalid
+	if ( $user_login !== $original_user_login ) {
+		$errors->add( 'user_name', __( '<strong>ERROR</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.' ) );
+	}
+
+	if ( is_multisite() ) {
+		// Check the user_login against an array of illegal names
+		$illegal_logins = get_site_option( 'illegal_names' );
+		if ( false == is_array( $illegal_logins ) ) {
+			$illegal_logins = array( 'www', 'web', 'root', 'admin', 'main', 'invite', 'administrator' );
+			add_site_option( 'illegal_names', $illegal_logins );
+		}
+		if ( in_array( $user_login, $illegal_logins ) ) {
+			$errors->add( 'user_name',  __( 'Sorry, that username is not allowed.' ) );
+		}
+	}
+
+	/** This filter is documented in wp-includes/user.php */
+	$illegal_logins = (array) apply_filters( 'illegal_user_logins', array() );
+
+	if ( in_array( strtolower( $user_login ), array_map( 'strtolower', $illegal_logins ) ) ) {
+		if ( is_multisite() ) {
+			$errors->add( 'user_name',  __( 'Sorry, that username is not allowed.' ) );
+		} else {
+			$errors->add( 'invalid_username',  __( 'Sorry, that username is not allowed.' ) );
+		}
+	}
+
+	if ( is_multisite() ) {
+		// User login must have at least one letter
+		if ( ! preg_match( '/[a-zA-Z]+/', $user_login ) ) {
+			$errors->add( 'user_name', __( 'Sorry, usernames must have letters too!' ) );
+		}
+	}
+
+	// Check if the username has been used already.
+	if ( username_exists( $user_login ) ) {
+		$errors->add( 'user_name', __( 'Sorry, that username already exists!' ) );
+	}
+
+	if ( is_multisite() ) {
+		// Has someone already signed up for this username?
+		$signup = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->signups WHERE user_login = %s", $user_login ) );
+		if ( $signup != null ) {
+			$registered_at =  mysql2date( 'U', $signup->registered );
+			$now = current_time( 'timestamp', true );
+			$diff = $now - $registered_at;
+			// If registered more than two days ago, cancel registration and let this signup go through.
+			if ( $diff > 2 * DAY_IN_SECONDS )
+				$wpdb->delete( $wpdb->signups, array( 'user_login' => $user_login ) );
+			else
+				$errors->add( 'user_name', __( 'That username is currently reserved but may be available in a couple of days.' ) );
+		}
+	}
+
+	/**
+	 * Filter whether the provided user_login is valid or not.
+	 *
+	 * @since 2.0.1
+	 *
+	 * @param bool   $valid      Whether given user_login is valid.
+	 * @param string $user_login user_login to check.
+	 */
+	$valid = apply_filters( 'validate_username', true, $user_login );
+	if ( ! $valid ) {
+		$errors->add( 'user_name', __( 'Sorry, that username is invalid.' ) );
+	}
+
+	/**
+	 * Validate a user_login. A user_login can be invalidated by adding an error
+	 * to the WP_Error.
+	 *
+	 * @since TBD
+	 *
+	 * @param  WP_Error $errors
+	 * @param  string   $user_login The user_login to validate.
+	 */
+	do_action( 'wp_validate_user_login', $errors, $user_login );
+
+	if ( $errors->errors ) {
+		return $errors;
+	} else {
+		return true;
+	}
+}
+
+/**
  * Handles registering a new user.
  *
  * @since 2.5.0
@@ -2240,7 +2366,6 @@
 function register_new_user( $user_login, $user_email ) {
 	$errors = new WP_Error();
 
-	$sanitized_user_login = sanitize_user( $user_login );
 	/**
 	 * Filters the email address of a user being registered.
 	 *
@@ -2250,23 +2375,9 @@
 	 */
 	$user_email = apply_filters( 'user_registration_email', $user_email );
 
-	// Check the username
-	if ( $sanitized_user_login == '' ) {
-		$errors->add( 'empty_username', __( '<strong>ERROR</strong>: Please enter a username.' ) );
-	} elseif ( ! validate_username( $user_login ) ) {
-		$errors->add( 'invalid_username', __( '<strong>ERROR</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.' ) );
-		$sanitized_user_login = '';
-	} elseif ( username_exists( $sanitized_user_login ) ) {
-		$errors->add( 'username_exists', __( '<strong>ERROR</strong>: This username is already registered. Please choose another one.' ) );
+	// Validate the username
+	wp_validate_user_login( $user_login, $errors );
 
-	} else {
-		/** This filter is documented in wp-includes/user.php */
-		$illegal_user_logins = array_map( 'strtolower', (array) apply_filters( 'illegal_user_logins', array() ) );
-		if ( in_array( strtolower( $sanitized_user_login ), $illegal_user_logins ) ) {
-			$errors->add( 'invalid_username', __( '<strong>ERROR</strong>: Sorry, that username is not allowed.' ) );
-		}
-	}
-
 	// Check the email address
 	if ( $user_email == '' ) {
 		$errors->add( 'empty_email', __( '<strong>ERROR</strong>: Please type your email address.' ) );
@@ -2282,13 +2393,13 @@
 	 *
 	 * @since 2.1.0
 	 *
-	 * @param string   $sanitized_user_login The submitted username after being sanitized.
-	 * @param string   $user_email           The submitted email.
-	 * @param WP_Error $errors               Contains any errors with submitted username and email,
-	 *                                       e.g., an empty field, an invalid username or email,
-	 *                                       or an existing username or email.
+	 * @param string   $user_login The submitted username after being sanitized.
+	 * @param string   $user_email The submitted email.
+	 * @param WP_Error $errors     Contains any errors with submitted username and email,
+	 *                             e.g., an empty field, an invalid username or email,
+	 *                             or an existing username or email.
 	 */
-	do_action( 'register_post', $sanitized_user_login, $user_email, $errors );
+	do_action( 'register_post', $user_login, $user_email, $errors );
 
 	/**
 	 * Filters the errors encountered when a new user is being registered.
@@ -2301,18 +2412,18 @@
 	 *
 	 * @since 2.1.0
 	 *
-	 * @param WP_Error $errors               A WP_Error object containing any errors encountered
-	 *                                       during registration.
-	 * @param string   $sanitized_user_login User's username after it has been sanitized.
-	 * @param string   $user_email           User's email.
+	 * @param WP_Error $errors     A WP_Error object containing any errors encountered
+	 *                             during registration.
+	 * @param string   $user_login User's username.
+	 * @param string   $user_email User's email.
 	 */
-	$errors = apply_filters( 'registration_errors', $errors, $sanitized_user_login, $user_email );
+	$errors = apply_filters( 'registration_errors', $errors, $user_login, $user_email );
 
 	if ( $errors->get_error_code() )
 		return $errors;
 
 	$user_pass = wp_generate_password( 12, false );
-	$user_id = wp_create_user( $sanitized_user_login, $user_pass, $user_email );
+	$user_id = wp_create_user( $user_login, $user_pass, $user_email );
 	if ( ! $user_id || is_wp_error( $user_id ) ) {
 		$errors->add( 'registerfail', sprintf( __( '<strong>ERROR</strong>: Couldn&#8217;t register you&hellip; please contact the <a href="mailto:%s">webmaster</a> !' ), get_option( 'admin_email' ) ) );
 		return $errors;
Index: src/wp-signup.php
===================================================================
--- src/wp-signup.php	(revision 38287)
+++ src/wp-signup.php	(working copy)
@@ -659,7 +659,7 @@
 	$errors = $filtered_results['errors'];
 
 	if ( empty($blogname) )
-		$blogname = $user_name;
+		$blogname = preg_replace( '|[ _.\-@]|i', '', strtolower($user_name) );
 	?>
 	<form id="setupform" method="post" action="wp-signup.php">
 		<input type="hidden" name="stage" value="validate-blog-signup" />
Index: tests/phpunit/tests/multisite/wpmuValidateUserSignup.php
===================================================================
--- tests/phpunit/tests/multisite/wpmuValidateUserSignup.php	(revision 37416)
+++ tests/phpunit/tests/multisite/wpmuValidateUserSignup.php	(working copy)
@@ -9,8 +9,8 @@
 	/**
 	 * @dataProvider data_user_name
 	 */
-	public function test_user_name( $user_name, $error_message ) {
-		$v = wpmu_validate_user_signup( $user_name, 'foo@example.com' );
+	public function test_user_name( $user_login, $error_message ) {
+		$v = wpmu_validate_user_signup( $user_login, 'foo@example.com' );
 		$this->assertContains( 'user_name', $v['errors']->get_error_codes(), $error_message );
 	}
 
@@ -18,13 +18,8 @@
 		return array(
 			array( 'contains spaces', 'User names with spaces are not allowed.' ),
 			array( 'ContainsCaps', 'User names with capital letters are not allowed.'  ),
-			array( 'contains_underscores', 'User names with underscores are not allowed.'  ),
 			array( 'contains%^*()junk', 'User names with non-alphanumeric characters are not allowed.'  ),
 			array( '', 'Empty user names are not allowed.'  ),
-			array( 'foo', 'User names of 3 characters are not allowed.'  ),
-			array( 'fo', 'User names of 2 characters are not allowed.'  ),
-			array( 'f', 'User names of 1 characters are not allowed.'  ),
-			array( 'f', 'User names of 1 characters are not allowed.'  ),
 			array( '12345', 'User names consisting only of numbers are not allowed.'  ),
 			array( 'thisusernamecontainsenoughcharacterstobelongerthan60characters', 'User names longer than 60 characters are not allowed.' ),
 		);
