diff --git a/lib/Redmine/DB/CTX.pm b/lib/Redmine/DB/CTX.pm
index 7babcfeefe0393eb75c65aca0a6fe7eabe0d1dc1..7b67c10d05ffebab0ec73666919c6b890fafeba0 100644
--- a/lib/Redmine/DB/CTX.pm
+++ b/lib/Redmine/DB/CTX.pm
@@ -32,7 +32,8 @@ sub sync_project
   my $sp_id= shift;
   my $dp_id= shift;
 
-  $ctx->sync_project_users ($sp_id, $dp_id);
+  # $ctx->sync_project_members ($sp_id, $dp_id);
+  $ctx->sync_project_user_preferences ($sp_id, $dp_id);
 }
 
 =head1 TRANSLATION
@@ -88,6 +89,7 @@ sub init_translation
   my $t;
   unless (defined ($t= $ctx->{'tlt'}))
   {
+    print "NOTE: loading syncs\n";
     $t= $ctx->{'tlt'}= {};
     my $d= $ctx->{'dst'}->get_all_x ('syncs', [ 'sync_context_id=?', $ctx->{'ctx_id'} ] );
     # print "d: ", main::Dumper ($d);
@@ -126,7 +128,7 @@ sub translate
   if (exists ($t->{$table_name}->{$src_id}))
   {
     my $x= $t->{$table_name}->{$src_id};
-    print "TRANSLATE: table_name=[$table_name] src_id=[$src_id] tlt=[",join(',',@$x),"]\n";
+    # TODO: if verbosity ... print "TRANSLATE: table_name=[$table_name] src_id=[$src_id] tlt=[",join(',',@$x),"]\n";
     return (wantarray) ? @$x : $x->[0];
   }
 
@@ -161,7 +163,7 @@ sub store_translation
   ($ctx->{'ctx_id'}, $table_name, $src_id, $dst_id); print "vals: ",
   join (',', @vals), "\n"; $sth->execute(@vals); $sth->finish();
 
-  $t->{$table_name}->{$src_id}= [ $dst_id, undef, 2 ];
+  $t->{$table_name}->{$src_id}= [ $dst_id, 2, undef ];
 }
 
 =head1 USERS
@@ -183,13 +185,13 @@ Synchronize the users and related tables.
 
 =cut
 
-sub sync_project_users
+sub sync_project_members
 {
   my $ctx= shift;
   my $sp_id= shift;
   my $dp_id= shift;
 
-  my ($ctx_id, $src, $dst)= map { $ctx->{$_} } qw(ctx_id src dst);
+  my ($src, $dst)= map { $ctx->{$_} } qw(src dst);
 
   # pcx means something like "project context"; TODO: change that name if a better one comes up...
   my $s_pcx= $src->pcx_members ($sp_id);
@@ -200,6 +202,20 @@ sub sync_project_users
   my ($s_members, $s_users)= map { $s_pcx->{$_} } qw(members users);
   my ($d_members, $d_users)= map { $d_pcx->{$_} } qw(members users);
 
+=begin comment
+
+TODO: A user might be already present on the destination Redmine instance,
+this code would try to import him anyway.  We need a method to verify
+that a user is already present, maybe some kind of logic like that
+implemented in sync_project_user_preferences below.
+
+For now, the operator would have to add the translations to the syncs
+table by hand.  If users would be imported on a fresh instance, this
+would not really be an issue.
+
+=end comment
+=cut
+
   # verbose Redmine::DB::MySQL (1);
 
   my @s_member_ids= (keys %$s_members);
@@ -375,6 +391,94 @@ sub clone_user
   \%user;
 }
 
+=head2 $context->sync_project_user_preferences($source_project_id, $destination_project_id)
+
+Sync preferences of users associated with a certain project.
+
+=cut
+
+sub sync_project_user_preferences
+{
+  my $ctx= shift;
+  my $sp_id= shift;
+  my $dp_id= shift;
+
+  my ($src, $dst)= map { $ctx->{$_} } qw(src dst);
+  my $st= $ctx->stats('user_preferences');
+
+  my $s_pref= $src->get_all_x ('user_preferences', [ 'user_id in (select user_id from members where project_id=?)', $sp_id ]);
+  my $s_up= reindex($s_pref, 'user_id');
+
+  # first: retrieve a list of translated user_id values:
+  my @s_uids= keys %$s_up;
+  my %s_uids;
+  my %d_uids; # user_id on destination with link to user_id on source and later a preference record on the source
+  foreach my $s_uid (@s_uids)
+  {
+    my $d_uid= $ctx->translate ('users', $s_uid);
+    # print "s_uid=[$s_uid] -> d_uid=[$d_uid]\n";
+    $st->{'cnt'}++;
+
+    if (defined ($d_uid))
+    {
+      $s_uids{$s_uid}= $d_uid;
+      $d_uids{$d_uid}= [ $s_uid ]; # link back to the source
+    }
+    else
+    { # not yet translated, maybe this user was not yet synced!
+      # TODO: call sync method for this user
+      # for now we assume that users were already synced
+      print "ATTN: user_id on source ($s_uid) not translated; maybe the member synchronization must be rerun!\n";
+      $st->{'missing'}++;
+      push (@{$st->{'missing_uid'}}, $s_uid);
+    }
+  }
+
+  # second: see if users with the translated user_id are already on the destination and link their preferences into %d_uids
+  # print "user_id mapping: ", main::Dumper (\%s_uids);
+  my @tlt_uids= map { $s_uids{$_} } keys %s_uids;
+# verbose Redmine::DB::MySQL (1);
+  my $d_pref= $dst->get_all_x ('user_preferences', [ 'user_id in ('.join(',',map { '?' } @tlt_uids).')', @tlt_uids ]);
+  # print "translated preferences: ", main::Dumper ($d_pref);
+  foreach my $d_id (keys %$d_pref)
+  {
+    my $x= $d_pref->{$d_id};
+    $d_uids{$x->{'user_id'}}->[1]= $x;
+  }
+
+  # finally: see which users have a preferences record and store it for those who don't have one yet.
+  foreach my $d_uid (keys %d_uids)
+  {
+    my $x= $d_uids{$d_uid};
+    print '-'x72, "\n";
+    print "d_uid=[$d_uid] ", main::Dumper ($x);
+
+    if (defined ($x->[1]))
+    {
+      $st->{'unchanged'}++;
+    }
+    else
+    { # no prefs record yet, copy it
+      my %d_prefs= %{$s_up->{$x->[0]}};
+
+      print "prefs on source: ", main::Dumper (\%d_prefs);
+
+      my $s_prefs_id= delete ($d_prefs{'id'});
+      $d_prefs{'user_id'}= $d_uid;
+
+      print "save new prefs: ", main::Dumper (\%d_prefs);
+
+      my $d_prefs_id= $dst->insert ('user_preferences', \%d_prefs);
+      # NOTE: do we need the translation at all?  possibly not, but what the heck
+      $ctx->store_translation('user_preferences', $s_prefs_id, $d_prefs_id);
+
+      $st->{'copied'}++;
+    }
+  }
+
+  $st;
+}
+
 sub sync_wiki
 {
 
@@ -391,6 +495,34 @@ sync wiki
 
 }
 
+=head1 INTERNAL METHODS?
+
+=cut
+
+sub stats
+{
+  my $self= shift;
+  my $what= shift;
+
+  my $t= $self->{'stats'}->{$what};
+     $t= $self->{'stats'}->{$what}= {} unless (defined ($t));
+  # print "accessing stats=[$what]: ", main::Dumper($self);
+  $t;
+}
+
+=head1 INTERNAL FUNCTIONS
+
+=cut
+
+sub reindex
+{
+  my $hash= shift;
+  my $key= shift;
+
+  my %res= map { my $x= $hash->{$_}; $x->{$key} => $x } keys %$hash;
+  \%res;
+}
+
 1;
 
 __END__
diff --git a/lib/Redmine/DB/MySQL.pm b/lib/Redmine/DB/MySQL.pm
index ab41c10a45f24f7bde0625342d4a497939c4de7f..d16e14658157efc213384c55a2c91665f67b1611 100644
--- a/lib/Redmine/DB/MySQL.pm
+++ b/lib/Redmine/DB/MySQL.pm
@@ -240,6 +240,21 @@ sub pcx_wiki
   $res;
 }
 
+sub pcx_user_preferences
+{
+  my $self= shift;
+  my $proj_id= shift;
+
+  my $res= $self->table('pcx');
+
+  # $show_query= 1;
+  my $pref= $self->get_all_x ('user_preferences', [ 'user_id in (select user_id from members where project_id=?)', $proj_id ]);
+
+  $res->{'user_preferences'}= $pref;
+
+  $res;
+}
+
 1;
 __END__
 
diff --git a/t_sync.pl b/t_sync.pl
index e20708b8d10a0b88a266373baa5d7846a7b8b4c7..86e882ff047cee4b570f5612bd84d30ee3cd120d 100755
--- a/t_sync.pl
+++ b/t_sync.pl
@@ -173,6 +173,8 @@ elsif ($op_mode eq 'sync')
 
     $ctx->sync_project ($sp->{'src_proj'}, $sp->{'dst_proj'});
   }
+
+  print "\n"x3, '='x72, "\n", "Statistics:", Dumper ($ctx->{'stats'});
 }
 elsif ($op_mode eq 'diag')
 {