diff --git src/wp-includes/user.php src/wp-includes/user.php
index 141fff3..1d00523 100644
--- src/wp-includes/user.php
+++ src/wp-includes/user.php
@@ -1676,12 +1676,17 @@ function wp_insert_user( $userdata ) {
 	if ( ! $update && username_exists( $user_login ) ) {
 		return new WP_Error( 'existing_user_login', __( 'Sorry, that username already exists!' ) );
 	}
-	if ( empty( $userdata['user_nicename'] ) ) {
-		$user_nicename = sanitize_title( $user_login );
+
+	// If a nicename is provided, remove unsafe user characters before
+	// using it. Otherwise build a nicename from the user_login.
+	if ( ! empty( $userdata['user_nicename'] ) ) {
+		$user_nicename = sanitize_user( $userdata['user_nicename'], true );
 	} else {
-		$user_nicename = $userdata['user_nicename'];
+		$user_nicename = $user_login;
 	}
 
+	$user_nicename = sanitize_title( $user_nicename );
+
 	// Store values to save in user meta.
 	$meta = array();
 
diff --git tests/phpunit/tests/user.php tests/phpunit/tests/user.php
index 26e45a2..5ca0a22 100644
--- tests/phpunit/tests/user.php
+++ tests/phpunit/tests/user.php
@@ -654,4 +654,19 @@ class Tests_User extends WP_UnitTestCase {
 		$metas = array_keys( get_user_meta( 1 ) );
 		$this->assertNotContains( 'key', $metas );
 	}
+
+	/**
+	 * @ticket 29696
+	 */
+	public function test_wp_insert_user_should_sanitize_user_nicename_parameter() {
+		$user = $this->factory->user->create_and_get();
+
+		$userdata = $user->to_array();
+		$userdata['user_nicename'] = str_replace( '-', '.', $user->user_nicename );
+		wp_insert_user( $userdata );
+
+		$updated_user = new WP_User( $user->ID );
+
+		$this->assertSame( $user->user_nicename, $updated_user->user_nicename );
+	}
 }
