Index: src/wp-admin/network/site-users.php
===================================================================
--- src/wp-admin/network/site-users.php	(revision 41125)
+++ src/wp-admin/network/site-users.php	(working copy)
@@ -66,16 +66,19 @@
 				if ( false === $user_id ) {
 		 			$update = 'err_new_dup';
 				} else {
-					add_user_to_blog( $id, $user_id, $_POST['new_role'] );
-					$update = 'newuser';
-					/**
-					  * Fires after a user has been created via the network site-users.php page.
-					  *
-					  * @since 4.4.0
-					  *
-					  * @param int $user_id ID of the newly created user.
-					  */
-					do_action( 'network_site_users_created_user', $user_id );
+					if ( is_wp_error( add_user_to_blog( $id, $user_id, $_POST['new_role'] ) ) ) {
+						$update = 'err_add_fail';
+					} else {
+						$update = 'newuser';
+						/**
+						  * Fires after a user has been created via the network site-users.php page.
+						  *
+						  * @since 4.4.0
+						  *
+						  * @param int $user_id ID of the newly created user.
+						  */
+						do_action( 'network_site_users_created_user', $user_id );
+					}
 				}
 			}
 			break;
@@ -87,10 +90,13 @@
 				$newuser = $_POST['newuser'];
 				$user = get_user_by( 'login', $newuser );
 				if ( $user && $user->exists() ) {
-					if ( ! is_user_member_of_blog( $user->ID, $id ) )
-						add_user_to_blog( $id, $user->ID, $_POST['new_role'] );
-					else
+					if ( ! is_user_member_of_blog( $user->ID, $id ) ) {
+						if ( is_wp_error( add_user_to_blog( $id, $user->ID, $_POST['new_role'] ) ) ) {
+							$update = 'err_add_fail';
+						}
+					} else {
 						$update = 'err_add_member';
+					}
 				} else {
 					$update = 'err_add_notfound';
 				}
@@ -223,6 +229,9 @@
 	case 'err_add_member':
 		echo '<div id="message" class="error notice is-dismissible"><p>' . __( 'User is already a member of this site.' ) . '</p></div>';
 		break;
+	case 'err_add_fail':
+		echo '<div id="message" class="error notice is-dismissible"><p>' . __( 'User could not be added to this site.' ) . '</p></div>';
+		break;
 	case 'err_add_notfound':
 		echo '<div id="message" class="error notice is-dismissible"><p>' . __( 'Enter the username of an existing user.' ) . '</p></div>';
 		break;
Index: src/wp-admin/user-new.php
===================================================================
--- src/wp-admin/user-new.php	(revision 41125)
+++ src/wp-admin/user-new.php	(working copy)
@@ -67,8 +67,12 @@
 		$redirect = add_query_arg( array('update' => 'addexisting'), 'user-new.php' );
 	} else {
 		if ( isset( $_POST[ 'noconfirmation' ] ) && current_user_can( 'manage_network_users' ) ) {
-			add_existing_user_to_blog( array( 'user_id' => $user_id, 'role' => $_REQUEST[ 'role' ] ) );
-			$redirect = add_query_arg( array( 'update' => 'addnoconfirmation' , 'user_id' => $user_id ), 'user-new.php' );
+			if ( ! is_wp_error( add_existing_user_to_blog( array( 'user_id' => $user_id, 'role' => $_REQUEST[ 'role' ] ) ) ) ) {
+				$redirect = add_query_arg( array( 'update' => 'addnoconfirmation' , 'user_id' => $user_id ), 'user-new.php' );
+			} else {
+				wp_redirect( add_query_arg( array( 'update' => 'could_not_add' ), 'user-new.php' ) );
+				die();
+			}
 		} else {
 			$newuser_key = substr( md5( $user_id ), 0, 5 );
 			add_option( 'new_user_' . $newuser_key, array( 'user_id' => $user_id, 'email' => $user_details->user_email, 'role' => $_REQUEST[ 'role' ] ) );
@@ -261,6 +265,9 @@
 			case "addexisting":
 				$messages[] = __('That user is already a member of this site.');
 				break;
+			case "could_not_add":
+				$messages[] = __( 'That user could not be added to this site.' );
+				break;
 			case "does_not_exist":
 				$messages[] = __('The requested user does not exist.');
 				break;
Index: src/wp-includes/ms-functions.php
===================================================================
--- src/wp-includes/ms-functions.php	(revision 41125)
+++ src/wp-includes/ms-functions.php	(working copy)
@@ -59,9 +59,10 @@
 		}
 	} else {
 		//TODO Review this call to add_user_to_blog too - to get here the user must have a role on this blog?
-		add_user_to_blog( $first_blog->userblog_id, $user_id, 'subscriber' );
-		update_user_meta( $user_id, 'primary_blog', $first_blog->userblog_id );
-		$primary = $first_blog;
+		if ( ! is_wp_error( add_user_to_blog( $first_blog->userblog_id, $user_id, 'subscriber' ) ) ) {
+			update_user_meta( $user_id, 'primary_blog', $first_blog->userblog_id );
+			$primary = $first_blog;
+		}
 	}
 
 	if ( ( ! is_object( $primary ) ) || ( $primary->archived == 1 || $primary->spam == 1 || $primary->deleted == 1 ) ) {
@@ -160,6 +161,25 @@
 		return new WP_Error( 'user_does_not_exist', __( 'The requested user does not exist.' ) );
 	}
 
+	/**
+	* Filters whether a user should be added to a blog. 
+	*
+	* @since 
+	*
+	* @param bool   $retval  True if the user should be added to the blog, otherwise WP_Error.
+	* @param int    $user_id User ID.
+	* @param string $role    User role.
+	* @param int    $blog_id Blog ID.
+	*/
+	$ok_to_add = apply_filters( 'can_add_user_to_blog', true, $user_id, $role, $blog_id );
+	if ( true !== $ok_to_add ) {
+		restore_current_blog();
+		if ( is_wp_error( $ok_to_add ) ) {
+			return $ok_to_add;
+		}
+		return new WP_Error( 'user_cannot_be_added', __( 'The user cannot be added to the blog.' ) );
+	}
+
 	if ( !get_user_meta($user_id, 'primary_blog', true) ) {
 		update_user_meta($user_id, 'primary_blog', $blog_id);
 		$site = get_site( $blog_id );
@@ -2081,15 +2101,17 @@
 	if ( is_array( $details ) ) {
 		$blog_id = get_current_blog_id();
 		$result = add_user_to_blog( $blog_id, $details[ 'user_id' ], $details[ 'role' ] );
-		/**
-		 * Fires immediately after an existing user is added to a site.
-		 *
-		 * @since MU
-		 *
-		 * @param int   $user_id User ID.
-		 * @param mixed $result  True on success or a WP_Error object if the user doesn't exist.
-		 */
-		do_action( 'added_existing_user', $details['user_id'], $result );
+		if ( ! is_wp_error( $result ) ) {
+			/**
+			 * Fires immediately after an existing user is added to a site.
+			 *
+			 * @since MU
+			 *
+			 * @param int   $user_id User ID.
+			 * @param mixed $result  True on success or a WP_Error object if the user doesn't exist.
+			 */
+			do_action( 'added_existing_user', $details['user_id'], $result );
+		}
 		return $result;
 	}
 }
@@ -2111,9 +2133,10 @@
 	if ( !empty( $meta[ 'add_to_blog' ] ) ) {
 		$blog_id = $meta[ 'add_to_blog' ];
 		$role = $meta[ 'new_role' ];
-		remove_user_from_blog($user_id, get_network()->site_id); // remove user from main blog.
-		add_user_to_blog( $blog_id, $user_id, $role );
-		update_user_meta( $user_id, 'primary_blog', $blog_id );
+		remove_user_from_blog( $user_id, get_network()->site_id ); // remove user from main blog.
+		if ( ! is_wp_error( add_user_to_blog( $blog_id, $user_id, $role ) ) ) {
+			update_user_meta( $user_id, 'primary_blog', $blog_id );
+		}
 	}
 }
 
Index: src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php
===================================================================
--- src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php	(revision 41125)
+++ src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php	(working copy)
@@ -503,7 +503,10 @@
 				return $user_id;
 			}
 
-			add_user_to_blog( get_site()->id, $user_id, '' );
+			$result= add_user_to_blog( get_site()->id, $user_id, '' );
+			if ( is_wp_error( $result ) ) {
+				return $result;
+			}
 		} else {
 			$user_id = wp_insert_user( wp_slash( (array) $user ) );
 
Index: tests/phpunit/tests/user/multisite.php
===================================================================
--- tests/phpunit/tests/user/multisite.php	(revision 41125)
+++ tests/phpunit/tests/user/multisite.php	(working copy)
@@ -398,6 +398,38 @@
 	}
 
 	/**
+	 * @ticket 41101
+	 */
+	public function test_should_fail_can_add_user_to_blog_filter() {
+		$site_id = self::factory()->blog->create();
+		$user_id = self::factory()->user->create();
+
+		add_filter( 'can_add_user_to_blog', '__return_false', 10, 4 );
+		$result = add_user_to_blog( $site_id, $user_id, 'subscriber' );
+
+		wpmu_delete_blog( $site_id );
+		wpmu_delete_user( $user_id );
+
+		$this->assertWPError( $result );
+	}
+
+	/**
+	 * @ticket 41101
+	 */
+	public function test_should_succeed_can_add_user_to_blog_filter() {
+		$site_id = self::factory()->blog->create();
+		$user_id = self::factory()->user->create();
+
+		add_filter( 'can_add_user_to_blog', '__return_true', 10, 4 );
+		$result = add_user_to_blog( $site_id, $user_id, 'subscriber' );
+
+		wpmu_delete_blog( $site_id );
+		wpmu_delete_user( $user_id );
+
+		$this->assertTrue( $result );
+	}
+
+	/**
 	 * @ticket 23016
 	 */
 	public function test_wp_roles_global_is_reset() {
