Adding and Removing Users in Drupal | OpsBlu Docs

Adding and Removing Users in Drupal

How to add and remove team members in Drupal. Covers invitation workflows, role assignment, access revocation, and user lifecycle management for analytics.

Overview

This guide covers the complete user lifecycle in Drupal: adding new users, managing user accounts, resetting passwords, blocking users, and properly removing user access. Learn best practices for user onboarding and offboarding.


Adding Users

Method 1: Manual User Creation (Admin UI)

Prerequisites:

  • Permission: Administer users
  • Access to: /admin/people

Steps:

  1. Navigate to Admin → People (/admin/people)
  2. Click Add user button
  3. Fill in required fields:
    • Username: Unique identifier
    • Email address: Must be unique
    • Password: Or check "Generate password"
    • Confirm password: (if entering manually)
  4. Configure optional settings:
    • Status: Active or Blocked
    • Roles: Select appropriate roles
    • Notify user: Send account creation email
  5. Click Create new account

Best Practices:

Good:

  • Use email as username for easier identification
  • Assign minimal required roles
  • Enable "Notify user of new account"
  • Generate strong password
  • Document reason for account creation

Avoid:

  • Creating accounts without notification
  • Using weak passwords
  • Giving administrator role immediately
  • Creating accounts without proper approval

Method 2: User Self-Registration

Configure Registration Settings:

Navigate to: /admin/config/people/accounts

Registration Options:

1. Administrators only (Default, most secure)

☑ Only site administrators can create new user accounts.

2. Visitors (with admin approval)

☑ Visitors can create accounts but administrator approval is required.
  • User registers at /user/register
  • Account created but blocked
  • Admin receives notification email
  • Admin must approve at /admin/people

3. Visitors (open registration)

☑ Visitors can create accounts and no administrator approval is required.
  • Risk of spam accounts
  • Requires CAPTCHA protection
  • Monitor for abuse

Enhance with CAPTCHA:

# Install CAPTCHA protection
composer require drupal/captcha drupal/recaptcha
drush en captcha recaptcha -y

Configure at: /admin/config/people/captcha

Method 3: Drush Command Line

# Create user with password
drush user:create johndoe --mail="john@example.com" --password="SecurePass123!"

# Create user and generate password
drush user:create janedoe --mail="jane@example.com"

# Create user with role
drush user:create editor1 --mail="editor@example.com" --password="Pass123" && \
drush user:role:add "content_editor" editor1

# Create multiple users in sequence
for user in user1 user2 user3; do
  drush user:create "$user" --mail="$user@example.com" --password="TempPass123"
  drush user:role:add "authenticated" "$user"
done

Method 4: Programmatic User Creation

Simple user creation:

<?php

use Drupal\user\Entity\User;

// Create user
$user = User::create([
  'name' => 'johndoe',
  'mail' => 'john@example.com',
  'pass' => 'SecurePassword123!',
  'status' => 1, // Active
  'roles' => ['content_editor'],
  'field_first_name' => 'John',
  'field_last_name' => 'Doe',
]);

$user->save();

// Get user ID
$uid = $user->id();

With error handling:

<?php

use Drupal\user\Entity\User;

try {
  // Check if username exists
  $existing = \Drupal::entityTypeManager()
    ->getStorage('user')
    ->loadByProperties(['name' => 'johndoe']);

  if (!empty($existing)) {
    throw new \Exception('Username already exists');
  }

  // Check if email exists
  $existing = \Drupal::entityTypeManager()
    ->getStorage('user')
    ->loadByProperties(['mail' => 'john@example.com']);

  if (!empty($existing)) {
    throw new \Exception('Email already exists');
  }

  // Create user
  $user = User::create([
    'name' => 'johndoe',
    'mail' => 'john@example.com',
    'pass' => 'SecurePassword123!',
    'status' => 1,
    'roles' => ['content_editor'],
  ]);

  $user->save();

  // Send notification email
  _user_mail_notify('register_admin_created', $user);

  \Drupal::logger('user_management')->info('Created user: @name', [
    '@name' => $user->getAccountName()
  ]);

} catch (\Exception $e) {
  \Drupal::logger('user_management')->error('Failed to create user: @error', [
    '@error' => $e->getMessage()
  ]);
}

Method 5: Bulk User Import

Using Feeds module:

composer require drupal/feeds drupal/feeds_ex
drush en feeds feeds_ex -y

Configure import:

  1. Navigate to /admin/structure/feeds
  2. Add feed type: User Import
  3. Select parser: CSV
  4. Configure mappings:
    • CSV Column → User field
    • email → Email address
    • username → Username
    • role → Roles

CSV format:

username,email,role,status,first_name,last_name
john.doe,john@example.com,content_editor,1,John,Doe
jane.smith,jane@example.com,site_manager,1,Jane,Smith
bob.jones,bob@example.com,authenticated,1,Bob,Jones

Import:

  1. Navigate to /import
  2. Choose User Import
  3. Upload CSV file
  4. Review mappings
  5. Import users

Managing Existing Users

Editing User Accounts

Via UI:

  1. Navigate to /admin/people
  2. Find user (use filters if needed)
  3. Click Edit
  4. Modify fields:
    • Email address
    • Username (if allowed)
    • Password
    • Roles
    • Status (Active/Blocked)
    • Custom fields
  5. Click Save

Via Drush:

# Change email
drush user:edit johndoe --mail="newemail@example.com"

# Change password
drush user:password johndoe "NewSecurePass123!"

# Add role
drush user:role:add "administrator" johndoe

# Remove role
drush user:role:remove "content_editor" johndoe

Programmatically:

<?php

use Drupal\user\Entity\User;

// Load user
$user = User::load(123);
// Or by username
$users = \Drupal::entityTypeManager()
  ->getStorage('user')
  ->loadByProperties(['name' => 'johndoe']);
$user = reset($users);

// Update fields
$user->setEmail('newemail@example.com');
$user->set('field_phone', '555-1234');
$user->addRole('editor');
$user->removeRole('content_creator');

// Save changes
$user->save();

Password Management

User Password Reset (Self-Service)

User-initiated:

  1. User goes to /user/login
  2. Clicks Reset your password
  3. Enters email address
  4. Receives password reset email
  5. Clicks link in email
  6. Sets new password

Configure reset email:

Navigate to: /admin/config/people/accounts → Emails tab → Password recovery

Customize template:

[user:display-name],

A request to reset the password for your account has been made at [site:name].

You may now log in by clicking this link or copying and pasting it into your browser:

[user:one-time-login-url]

This link can only be used once to log in and will lead you to a page where you can set your password.

If you did not request this email, please ignore it.

--  [site:name] team

Admin Password Reset

Via UI:

  1. Navigate to /admin/people
  2. Find user
  3. Click Edit
  4. Enter new password in Password field
  5. Confirm password
  6. Check "Notify user of new password" (optional)
  7. Click Save

Via Drush:

# Set specific password
drush user:password johndoe "NewPassword123"

# Generate random password
drush user:password johndoe --password=$(openssl rand -base64 12)

# Generate one-time login link
drush user:login johndoe
# Returns: http://example.com/user/reset/1/1234567890/abcdef...

Programmatically:

<?php

use Drupal\user\Entity\User;

// Load user
$user = User::load(123);

// Set password
$user->setPassword('NewSecurePassword123!');
$user->save();

// Or use password hasher
$password_hasher = \Drupal::service('password');
$hashed = $password_hasher->hash('PlainTextPassword');
$user->pass = $hashed;
$user->save();

// Generate one-time login link
$timestamp = \Drupal::time()->getRequestTime();
$login_link = user_pass_reset_url($user);

Force Password Change

Using Password Policy module:

composer require drupal/password_policy
drush en password_policy password_policy_expire -y

Configure at: /admin/config/security/password-policy

Or manually:

<?php

use Drupal\user\Entity\User;

// Force password change on next login
$user = User::load(123);
$user->set('field_force_password_change', TRUE);
$user->save();

// Check on login
function mymodule_user_login(User $account) {
  if ($account->get('field_force_password_change')->value) {
    \Drupal::messenger()->addWarning('You must change your password.');
    // Redirect to password change form
    return new RedirectResponse('/user/' . $account->id() . '/edit');
  }
}

Blocking Users

Why Block Instead of Delete

Block when:

  • Temporary suspension needed
  • User may return
  • Content ownership must be preserved
  • Investigation required

Delete when:

  • Permanent removal requested
  • Compliance requirements (GDPR)
  • Spam/bot accounts

Blocking via UI

Single user:

  1. Navigate to /admin/people
  2. Find user
  3. Click Edit
  4. Under Status, select Blocked
  5. Click Save

Bulk blocking:

  1. Navigate to /admin/people
  2. Select users (checkboxes)
  3. Choose Block the selected user(s) from dropdown
  4. Click Apply to selected items

Blocking via Drush

# Block user
drush user:block johndoe

# Unblock user
drush user:unblock johndoe

# Check user status
drush user:information johndoe

Blocking Programmatically

<?php

use Drupal\user\Entity\User;

// Block user
$user = User::load(123);
$user->block();
$user->save();

// Unblock user
$user->activate();
$user->save();

// Check status
if ($user->isBlocked()) {
  // User is blocked
}

Automatic Blocking

Block after failed login attempts:

composer require drupal/flood_control
drush en flood_control -y

Configure at: /admin/config/system/flood-control

Block inactive accounts:

composer require drupal/autoblock
drush en autoblock -y

Configure at: /admin/config/people/autoblock


Removing Users

Understanding Deletion Options

Navigate to: /admin/config/people/accounts → Account Cancellation tab

Options:

1. Disable the account and keep its content

☐ Disable account and keep content
  • Account blocked (not deleted)
  • All content remains attributed to user
  • Can be re-enabled later

2. Disable the account and unpublish its content

☐ Disable account and unpublish content
  • Account blocked
  • All created content unpublished
  • Content still owned by user

3. Delete the account and make its content belong to Anonymous

☐ Delete account, reassign content to Anonymous
  • Account permanently deleted
  • Content ownership transferred to Anonymous
  • Cannot be reversed

4. Delete the account and its content

☐ Delete account and all content
  • Complete removal
  • All content deleted
  • Cannot be reversed
  • Use with extreme caution

Deleting via UI

Single user:

  1. Navigate to /admin/people
  2. Find user
  3. Click Edit
  4. Scroll to bottom
  5. Click Cancel account
  6. Select deletion method
  7. Confirm deletion

Bulk deletion:

  1. Navigate to /admin/people
  2. Select users (checkboxes)
  3. Choose Cancel the selected user accounts from dropdown
  4. Click Apply to selected items
  5. Select deletion method
  6. Confirm

Deleting via Drush

# Cancel user (requires confirmation)
drush user:cancel johndoe

# Force deletion without confirmation
drush user:cancel johndoe --delete-content -y

# Cancel multiple users
drush user:cancel user1,user2,user3 -y

Deleting Programmatically

<?php

use Drupal\user\Entity\User;

// Load user
$user = User::load(123);

// Delete user and keep content
$user->delete();

// Delete user and content
// First, delete user's content
$nids = \Drupal::entityQuery('node')
  ->condition('uid', $user->id())
  ->accessCheck(FALSE)
  ->execute();

$storage = \Drupal::entityTypeManager()->getStorage('node');
$nodes = $storage->loadMultiple($nids);
$storage->delete($nodes);

// Then delete user
$user->delete();

Proper User Offboarding Checklist

Before deletion:

  • Document reason for removal
  • Transfer content ownership to active user
  • Export user data if needed for records
  • Reassign tasks/workflows to other users
  • Revoke API keys if any
  • Remove from external systems (SSO, LDAP, etc.)
  • Notify stakeholders of account removal
  • Wait period for any objections (e.g., 30 days)

During deletion:

  • Choose appropriate deletion method
  • Block account first (test impact)
  • Export final content list owned by user
  • Document deletion in ticket/log
  • Screenshot proof of deletion

After deletion:

  • Verify removal from user list
  • Check content attribution correct
  • Audit permissions removed
  • Update documentation (remove from contact lists, etc.)

User Data Export (GDPR Compliance)

Export User Data

Using Views Data Export:

composer require drupal/views_data_export
drush en views_data_export -y

Create export view:

  1. Navigate to /admin/structure/views/add
  2. Show: Users
  3. Display: Data export
  4. Format: CSV or JSON
  5. Fields: Email, Username, Created, Roles, Custom fields
  6. Path: /admin/reports/user-export
  7. Save

Export specific user:

# Via Drush (custom command)
drush user:export johndoe > user-johndoe-export.json

Programmatically:

<?php

use Drupal\user\Entity\User;

// Load user
$user = User::load(123);

// Gather all user data
$export = [
  'account' => [
    'uid' => $user->id(),
    'name' => $user->getAccountName(),
    'mail' => $user->getEmail(),
    'created' => $user->getCreatedTime(),
    'changed' => $user->getChangedTime(),
    'status' => $user->isActive(),
    'roles' => $user->getRoles(),
  ],
  'fields' => [],
];

// Export custom fields
foreach ($user->getFields() as $field_name => $field) {
  if (!in_array($field_name, ['uid', 'name', 'mail', 'pass', 'init'])) {
    $export['fields'][$field_name] = $user->get($field_name)->getValue();
  }
}

// Export user's content
$nids = \Drupal::entityQuery('node')
  ->condition('uid', $user->id())
  ->accessCheck(FALSE)
  ->execute();

$export['content'] = [
  'count' => count($nids),
  'node_ids' => array_values($nids),
];

// Convert to JSON
$json = json_encode($export, JSON_PRETTY_PRINT);
file_put_contents("user-{$user->id()}-export.json", $json);

Bulk Operations

Using Views Bulk Operations

composer require drupal/views_bulk_operations
drush en views_bulk_operations -y

Features:

  • Select multiple users
  • Apply actions in bulk
  • Custom actions
  • Batch processing

Custom Bulk Actions

Create bulk add role action:

<?php

namespace Drupal\mymodule\Plugin\Action;

use Drupal\Core\Action\ActionBase;
use Drupal\Core\Session\AccountInterface;

/**
 * Adds a specific role to users.
 *
 * @Action(
 *   id = "add_custom_role",
 *   label = @Translation("Add Marketing role"),
 *   type = "user"
 * )
 */
class AddMarketingRole extends ActionBase {

  public function execute($account = NULL) {
    $account->addRole('marketing_manager');
    $account->save();
  }

  public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
    return $object->access('update', $account, $return_as_object);
  }
}

Automation & Workflows

Automatic User Creation on Form Submission

<?php

use Drupal\user\Entity\User;
use Drupal\webform\WebformSubmissionInterface;

/**
 * Implements hook_webform_submission_insert().
 */
function mymodule_webform_submission_insert(WebformSubmissionInterface $submission) {
  $webform_id = $submission->getWebform()->id();

  if ($webform_id === 'user_registration') {
    $data = $submission->getData();

    // Create user from form data
    $user = User::create([
      'name' => $data['username'],
      'mail' => $data['email'],
      'pass' => user_password(12),
      'status' => 0, // Blocked until approved
      'field_company' => $data['company'],
      'field_phone' => $data['phone'],
    ]);

    $user->save();

    // Notify admin
    $mailManager = \Drupal::service('plugin.manager.mail');
    $mailManager->mail(
      'mymodule',
      'new_user_pending',
      'admin@example.com',
      'en',
      ['user' => $user]
    );
  }
}

Scheduled User Cleanup

<?php

/**
 * Implements hook_cron().
 */
function mymodule_cron() {
  // Delete users inactive for 1 year
  $one_year_ago = strtotime('-1 year');

  $uids = \Drupal::entityQuery('user')
    ->condition('access', $one_year_ago, '<')
    ->condition('uid', 1, '>')
    ->condition('status', 1)
    ->accessCheck(FALSE)
    ->execute();

  if (!empty($uids)) {
    $storage = \Drupal::entityTypeManager()->getStorage('user');
    $users = $storage->loadMultiple($uids);

    foreach ($users as $user) {
      // Block first (don't delete immediately)
      $user->block();
      $user->save();

      // Log for review
      \Drupal::logger('user_cleanup')->info('Blocked inactive user: @name', [
        '@name' => $user->getAccountName()
      ]);
    }
  }
}

Troubleshooting

Can't Delete User

Error: "User cannot be deleted"

Causes:

  • User owns content
  • User ID 1 (super admin)
  • User referenced in other entities

Solution:

  1. Reassign content first
  2. Remove references
  3. Use cancellation instead of deletion

Duplicate Email

Error: "Email already in use"

Solution:

# Find user with email
drush user:list --mail="duplicate@example.com"

# Either delete duplicate or change email
drush user:edit user1 --mail="new-email@example.com"

Can't Log In After Creation

Causes:

  • Account blocked
  • Password not set
  • Email not verified

Solution:

# Check user status
drush user:information username

# Unblock if needed
drush user:unblock username

# Generate login link
drush user:login username

Resources


Next Steps


Quick Reference

Essential Commands

# Create user
drush user:create USERNAME --mail="EMAIL" --password="PASS"

# Add role
drush user:role:add "ROLE" USERNAME

# Block user
drush user:block USERNAME

# Unblock user
drush user:unblock USERNAME

# Delete user
drush user:cancel USERNAME --delete-content -y

# Reset password
drush user:password USERNAME "NEWPASS"

# One-time login
drush user:login USERNAME

# List users
drush user:list