I want to migrate some users from my Drupal 7 installation to a new Drupal 8 installation. I do not want to migrate the whole site or any content. And I also do not want to migrate all users.

The problem is the password; I can export from Drupal 7 and import users to Drupal 8, but the passwords do not work anymore. I've also tried to update the hashes (password) in the database directly; so I copied the password fields from Drupal 7 to Drupal 8. That also doesn't work; I think the salt changed in Drupal 8.

Is there any solution for this?

  • Looks like this is being worked on here drupal.org/node/2598038 - you should try a newer version of Drupal 8 if you are not on 8.2.x
    – George
    Commented Aug 2, 2016 at 13:22

2 Answers 2


Sorry for the confusion. Clarification:

Copying over the hashes from D7 to D8 works (I made a mistake with a backslash in the JSON output)!

So just copy over the D7 hashes (starting with $S$) from the D7.users.pass field to the D8.users_field_data.pass field. It will work. The first time, that the users logs in to the new D8 site, the password gets rehashed with the D8 algorithm (PhpassHashedPassword.check() and PhpassHashedPassword.needsRehash() are doing the magic).

Everything is fine :-) Thanks.

EDIT: Someone requested the code for this...

Here is my controller class that imports all the Drupal 7 users found in the file asde2.users.json:

  public function importAsde2Users() {
    // load asde2 user file
    $usersfile = $_SERVER['DOCUMENT_ROOT']."/".drupal_get_path('module', 'preosuser')."/asde2.users.json";
    PxLog::debug($this, "Loading asde2 users file ".$usersfile);
    // decode json array of objects
    $users = json_decode(file_get_contents($usersfile));
    PxLog::debug($this, "Found ".count($users)." Users in that file");
    $database = \Drupal::database();
    // import all of them
    foreach ($users as $user) {
      $newuser = \Drupal\user\Entity\User::create([
          'name' => $user->name,
          'pass' => $user->pass,
          'mail' => $user->mail,
          'status' => $user->status,
          'init' => $user->init,
          'created' => $user->created,
          'login' => $user->login,
          'access' => $user->access,
          'uid' => $user->uid,
      // dirty overwrite re-hashed hash
        ->fields(['pass' => $user->pass])
        ->keys(array('uid' => $user->uid))

    return ['#markup' => "Created ".count($users)." Users with that file", '#cache' => ['max-age' => 0]];

Have fun.

  • Did this with D8.1.1 - Minimal (minimal-8.1.1) Commented Aug 2, 2016 at 13:25
  • Thanks a lot man! It's hacky but it works. Commented Apr 19, 2020 at 11:31
  • Thanks @RainerFeike! Confirmed that this "dirty trick" still works with Drupal 8.9. Commented Dec 30, 2020 at 21:50

This issue appears to have been resolved in: https://www.drupal.org/node/2598038

which was merged into core as of 8.1.4.

In order to preserve pre-hashed passwords, add the following to your migration YAML file:

  plugin: entity:user
  pre_hashed: true

Not the answer you're looking for? Browse other questions tagged or ask your own question.