How to Preserve File Permissions and Ownership When Using SCP as Root


2 views

When transferring files between Linux servers using SCP, many administrators encounter situations where the -p flag doesn't fully preserve ownership as expected. This becomes particularly problematic when:

  • Copying system files owned by specific service users (like mysql, postgres, or www-data)
  • Operating as root due to security constraints
  • Maintaining consistent permissions across environments

The -p option in SCP preserves:

* Modification times
* Access times
* Modes (permission bits)

However, it doesn't preserve ownership because:

  1. SCP doesn't have privilege escalation mechanisms
  2. The remote server's user/group database might differ
  3. Security restrictions prevent arbitrary ownership changes

Option 1: Post-transfer chown

After the transfer, modify ownership:

scp -p /mysql/serv/data_summary.* some_server:/mysql/test/
ssh some_server "chown -R mysql:mysql /mysql/test/"

Option 2: rsync with sudo

For more reliable permission handling:

rsync -avz --chown=mysql:mysql /mysql/serv/data_summary.* some_server:/mysql/test/

Note: This requires sudoers configuration allowing passwordless sudo for specific commands.

For complete metadata preservation:

rsync -aAXvz --numeric-ids --rsync-path="sudo rsync" \
      /mysql/serv/data_summary.* some_server:/mysql/test/

Key flags explanation:

  • -a: archive mode (preserves almost everything)
  • -A: preserves ACLs
  • -X: preserves extended attributes
  • --numeric-ids: uses IDs instead of names for ownership

When implementing these solutions:

  • Limit sudo permissions to specific commands
  • Consider using SSH certificates instead of passwords
  • Audit permission changes regularly

When transferring files between Linux servers using SCP, a common frustration occurs when file ownership and permissions don't carry over as expected - even when using the -p flag. This becomes particularly problematic when:

  • Moving system files owned by specific services (like mysql)
  • Root is required for the transfer due to admin policies
  • The destination server needs identical ownership for proper functionality

The -p flag in SCP preserves:

 - Modification times
 - Access times
 - Mode (permission bits)

However, it cannot preserve ownership because:

  1. SCP doesn't have the capability to map UIDs/GIDs between different systems
  2. The remote system might not have matching user/group IDs
  3. Even as root, SCP doesn't attempt to modify ownership during transfer

Here are three effective methods to achieve proper ownership preservation:

Method 1: Post-transfer chown

After SCP transfer, modify ownership:

scp -p /mysql/serv/data_summary.* some_server:/mysql/test/
ssh some_server "chown -R mysql:mysql /mysql/test/data_summary.*"

Method 2: rsync with --chown

rsync provides more granular control:

rsync -avp --chown=mysql:mysql /mysql/serv/data_summary.* some_server:/mysql/test/

Key advantages:

  • Preserves all attributes including ownership
  • Allows explicit ownership specification
  • Supports incremental transfers

Method 3: Tar Pipe with Ownership Preservation

For complex transfers, consider:

(cd /mysql/serv && tar cf - data_summary.*) | \
ssh some_server "cd /mysql/test && tar xpf - --same-owner"

When implementing these solutions:

  • Ensure the mysql user exists on both systems with matching UIDs
  • Verify the destination directory permissions allow ownership changes
  • Consider using --numeric-ids with rsync if UIDs differ between systems
  • For large transfers, monitor progress with pv or rsync --progress

For frequent transfers, create a bash script:

#!/bin/bash
SOURCE_PATH="/mysql/serv/data_summary.*"
DEST="some_server:/mysql/test/"

rsync -avp --chown=mysql:mysql ${SOURCE_PATH} ${DEST} || {
  echo "rsync failed, falling back to scp+chown" >&2
  scp -p ${SOURCE_PATH} ${DEST}
  ssh ${DEST%:*} "chown mysql:mysql ${DEST#*:}data_summary.*"
}