All Products
Search
Document Center

ApsaraDB RDS:Instance-level migration of SQL Server to the cloud

Last Updated:Mar 28, 2026

ApsaraDB RDS for SQL Server supports instance-level migration, letting you move multiple or all databases from a self-managed SQL Server instance in a single operation. Back up all databases, upload the backup files to an OSS bucket, then run the migration script.

Important

This solution supports full migration only. Incremental migration is not supported. Do not write new data to the source instance during the backup.

Note

This topic covers instance-level migration only, which migrates all databases at once as full backups. To migrate a single database — including incremental backups — see Migrating full backups to the cloud and Migrating incremental backups to the cloud.

How it works

The migration follows three stages:

  1. Back up — Run the backup script on your self-managed SQL Server instance to produce full backup files (.bak) for all databases.

  2. Upload — Upload all backup files into the same folder in an OSS bucket that is in the same region as your destination RDS instance.

  3. Migrate — Run the migration script to create migration tasks. RDS reads the backup files from OSS and restores each database.

Prerequisites

Before you begin, make sure:

  • The source database is a self-managed SQL Server instance.

  • The destination ApsaraDB RDS for SQL Server instance meets the following conditions:

    • Available storage space is greater than the total size of the data files to be migrated. If space is insufficient, upgrade the instance specifications before proceeding.

    • SQL Server 2008 R2 only: Create databases on the destination instance with the same names as the databases to be migrated. For SQL Server 2012 and later, a database with the same name cannot already exist.

  • If you use a Resource Access Management (RAM) user:

    • The RAM user has the AliyunOSSFullAccess and AliyunRDSFullAccess permissions. For details, see Manage OSS permissions using RAM and Manage ApsaraDB RDS permissions using RAM.

    • Your Alibaba Cloud account has granted the ApsaraDB RDS service account access to your OSS resources. To verify or grant this authorization: If the message You have authorized RDS official service account to access your OSS appears in the lower-left corner, authorization is complete. Otherwise, click the Authorization URL on the page. image

      1. On the Backup and Restoration page of your RDS instance, click Migrate OSS Backup Data to RDS.

      2. In the Import Guide, click Next twice to reach step 3. Import Data.

    • Your Alibaba Cloud account must create a custom access policy and attach it to the RAM user:

      View policy content

      {
          "Version": "1",
          "Statement": [
              {
                  "Action": [
                      "ram:GetRole"
                  ],
                  "Resource": "acs:ram:*:*:role/AliyunRDSImportRole",
                  "Effect": "Allow"
              }
          ]
      }

Billing

You are charged only for OSS bucket usage.

image
ScenarioBilling rule
Upload backup files to an OSS bucketFree of charge
Store backup files in an OSS bucketStorage fees apply. See the OSS pricing page.
Migrate backup files from OSS to RDS over the internal networkFree of charge
Migrate backup files from OSS to RDS over the InternetCharged based on OSS outbound traffic. See the OSS pricing page.

Preparations

Complete these steps on the machine where you will run the migration script.

1. Install Python 3

Download and install Python 3 from the official Python website. Select Python 3.12 or later.

  • Windows: During installation, select the Add python.exe to PATH checkbox to avoid manually configuring environment variables.

  • macOS or Linux: Install from the official website or use a package manager such as Homebrew, apt, or dnf.

2. Verify the Python installation

The executable name varies by operating system and installation method. Try the following commands in order and use the one that works on your system.

Windows (Command Prompt or PowerShell):

python --version
python3 --version
py --version
  • The output should show Python 3.12.x or later. On some systems, python still points to Python 2 — use python3 in that case.

  • If you see 'python' is not recognized as an internal or external command, add the Python installation directory to your system's PATH environment variable.

macOS/Linux (Terminal):

python --version
python3 --version

3. Install SDK dependencies

pip install alibabacloud_rds20140815
pip install alibabacloud-oss-v2

Step 1: Back up all databases

Important
  • To maintain data consistency, do not write new data to the source instance during the backup.

  • If you create backups manually without the backup script, name each file in the format DatabaseName_BackupType_BackupTime.bak — for example, Testdb_FULL_20180518153544.bak. Incorrect naming causes the migration to fail.

  1. Download the backup script.

  2. Open the script in SQL Server Management Studio (SSMS). For connection instructions, see the SSMS quickstart.

  3. Modify the parameters as needed:

    Click to view an example

    SELECT
        /**
        * Databases list needed to backup, delimiter is : or ,
        * empty('') or null: means all databases excluding system database
        * example: '[testdb]: TestDR, Test, readonly'
        **/
        @backup_databases_list = N'[dtstestdata],[testdb]'
        @backup_type = N'FULL',                    -- Backup Type? FULL: FULL backup; DIFF: Differential backup; LOG: Log backup
        @backup_folder = N'C:\BACKUP'              -- Backup folder to store backup files.
        @is_run = 1                                -- Check or run? 1, run directly; 0, just check
    ParameterDescription
    @backup_databases_listDatabases to back up. Separate multiple databases with semicolons (;) or commas (,). Leave blank to back up all non-system databases.
    @backup_typeBackup type. Set to FULL for this migration.
    @backup_folderLocal folder for backup files. The folder is created automatically if it does not exist.
    @is_run1 — perform the backup; 0 — check only without backing up.
  4. Run the script. Backup files are saved to the specified folder.

    Backup script execution result

Step 2: Upload backup files to OSS

All backup files must be in the same folder within an OSS bucket that is in the same region as your ApsaraDB RDS instance. Using the same region enables internal network transfer, which is free and faster than transferring over the Internet.

Prepare the OSS bucket

If a bucket already exists, verify that it meets these requirements:

  • Storage class: Standard. Infrequent Access, Archive, Cold Archive, and Deep Cold Archive are not supported.

  • Server-side encryption: Disabled.

If no bucket exists, activate OSS and then create one:

  1. Log on to the OSS console, click Buckets, and then click Create Bucket.

  2. Configure these parameters. Leave all others at their default values.

    Important

    - Create this bucket specifically for the migration. Delete it after migration is complete to prevent data exposure and reduce costs. - Do not enable server-side encryption when creating the bucket.

    ParameterDescriptionExample
    Bucket nameGlobally unique name that cannot be changed after creation. Use only lowercase letters, digits, and hyphens (-); start and end with a letter or digit; 3–63 characters.migratetest
    RegionMust match the region of your ApsaraDB RDS instance.China (Hangzhou)
    Storage classSelect Standard.Standard

Upload the backup files

Choose the upload method based on file size and your operating system:

Use ossbrowser (recommended for most cases)

  1. Download ossbrowser.

  2. Extract the downloaded package and launch oss-browser.exe (Windows x64 example).

  3. Select Log On With AK, enter your AccessKey ID and AccessKey secret, keep the default values for other fields, and click Log On.

    Note

    An AccessKey pair is used for identity verification. Keep it confidential.

    Log on to ossbrowser

  4. Click the destination bucket.

    Enter the bucket

  5. Click Upload icon, select the backup files, and click Open.

Use the OSS console (files smaller than 5 GB)

  1. Log on to the OSS console.

  2. Click Buckets, then click the name of the destination bucket.

    Enter the bucket from the console

  3. In the Objects list, click Upload Object.

    Upload object

  4. Drag backup files to the Files to Upload area, or click Select Files.

    Select files

  5. Click Upload Object at the bottom of the page.

Use the OSS API for multipart upload (files larger than 5 GB)

Set the following environment variables before running the script:

VariableDescription
OSS_ACCESS_KEY_IDYour AccessKey ID
OSS_ACCESS_KEY_SECRETYour AccessKey secret
OSS_SESSION_TOKEN (or OSS_SECURITY_TOKEN)STS session token, if using STS credentials
# -*- coding: utf-8 -*-
"""
Alibaba Cloud OSS Python SDK v2
Dependency: pip install alibabacloud-oss-v2
"""

import os
import sys
from pathlib import Path
import alibabacloud_oss_v2 as oss
from alibabacloud_oss_v2 import exceptions as oss_ex


def get_client_from_env(region: str, endpoint: str | None = None) -> oss.Client:
    """
    Create a v2 client from environment variables.
    - Prioritize using Region (recommended), but also support custom Endpoints (optional).
    - Compatible with both AK and STS:
        * AK: Requires OSS_ACCESS_KEY_ID / OSS_ACCESS_KEY_SECRET
        * STS: Also requires OSS_SESSION_TOKEN (compatible with the old variable OSS_SECURITY_TOKEN)
    """
    # Compatibility: If the user uses the old variable OSS_SECURITY_TOKEN, map it to the v2 expected OSS_SESSION_TOKEN
    sec_token_legacy = os.getenv("OSS_SECURITY_TOKEN")
    if sec_token_legacy and not os.getenv("OSS_SESSION_TOKEN"):
        os.environ["OSS_SESSION_TOKEN"] = sec_token_legacy

    ak = os.getenv("OSS_ACCESS_KEY_ID")
    sk = os.getenv("OSS_ACCESS_KEY_SECRET")
    st = os.getenv("OSS_SESSION_TOKEN")  # STS Token (optional)

    if not (ak and sk):
        raise ValueError("No valid AK found. Set the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables. "
                         "If using STS, also set OSS_SESSION_TOKEN (or the old name OSS_SECURITY_TOKEN).")

    # Indicate the type of credential used
    if st:
        print("STS Token (OSS_SESSION_TOKEN) detected. Using STS credentials.")
    else:
        print("No STS Token detected. Using AccessKey (AK) credentials.")

    credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
    cfg = oss.config.load_default()
    cfg.credentials_provider = credentials_provider

    # Basic network configuration
    cfg.region = region  # Example: 'cn-hangzhou'
    if endpoint:
        # Optional: Custom Endpoint (e.g., internal network, accelerated, dedicated domain)
        cfg.endpoint = endpoint

    # You can also add other configurations here, such as: cfg.use_accelerate_endpoint = True
    return oss.Client(cfg)


def resumable_upload_file_v2(
    client: oss.Client,
    bucket_name: str,
    object_key: str,
    file_path: str,
    part_size: int = 1 * 1024 * 1024,
    parallel_num: int = 4,
    checkpoint_dir: str | None = None,
):
    """
    Implement concurrent multipart upload with resumable upload.

    :param client: Initialized oss.Client
    :param bucket_name: Destination bucket name
    :param object_key: Destination object key (without bucket name)
    :param file_path: Full path of the local file
    :param part_size: Part size in bytes, default is 1 MB
    :param parallel_num: Number of concurrent upload threads, default is 4
    :param checkpoint_dir: Directory to store breakpoint information; if None, resumable upload is disabled
    """
    file_path = str(file_path)
    if not Path(file_path).exists():
        raise FileNotFoundError(f"Error: Local file not found. Check the file_path configuration: {file_path}")

    # Construct the Uploader; enable resumable upload based on whether checkpoint_dir is provided
    if checkpoint_dir:
        uploader = client.uploader(
            enable_checkpoint=True,
            checkpoint_dir=checkpoint_dir,
            part_size=part_size,
            parallel_num=parallel_num,
        )
    else:
        uploader = client.uploader(
            part_size=part_size,
            parallel_num=parallel_num,
        )

    print(f"Starting to upload file: {file_path}")
    print(f"Destination Bucket: {bucket_name}")
    print(f"Destination Object: {object_key}")
    print(f"Part size: {part_size} bytes, Concurrency: {parallel_num}")
    if checkpoint_dir:
        print(f"Resumable upload: Enabled (checkpoint_dir={checkpoint_dir})")
    else:
        print("Resumable upload: Disabled (set checkpoint_dir to enable)")

    # Execute the upload (Uploader automatically chooses between multi/single part concurrent upload based on size)
    result = uploader.upload_file(
        oss.PutObjectRequest(bucket=bucket_name, key=object_key),
        filepath=file_path,
    )

    print("-" * 30)
    print("File uploaded successfully!")
    print(f"HTTP Status: {result.status_code}")
    print(f"ETag: {result.etag}")
    print(f"Request ID: {result.request_id}")
    # CRC-64 checksum; v2 enables data validation by default
    print(f"CRC64: {result.hash_crc64}")
    print("-" * 30)


def main():
    # Before running the code example, make sure you have set the corresponding environment variables.
    # macOS/Linux:
    #   AK method:
    #     export OSS_ACCESS_KEY_ID=YOUR_AK_ID
    #     export OSS_ACCESS_KEY_SECRET=YOUR_AK_SECRET
    #   STS method:
    #     export OSS_ACCESS_KEY_ID=YOUR_STS_ID
    #     export OSS_ACCESS_KEY_SECRET=YOUR_STS_SECRET
    #     export OSS_SECURITY_TOKEN=YOUR_STS_TOKEN
    #
    # Windows:
    #   Powershell: $env:OSS_ACCESS_KEY_ID="YOUR_AK_ID"
    #   cmd: set OSS_ACCESS_KEY_ID=YOUR_AK_ID

    # ===================== Parameters (modify as needed) =====================
    # Region example: 'cn-hangzhou'; use Region first
    region = "cn-hangzhou"

    # Optional: Custom Endpoint (for internal network, dedicated domain, accelerated domain name, etc.)
    # Example: 'https://oss-cn-hangzhou.aliyuncs.com'
    endpoint = 'https://oss-cn-hangzhou.aliyuncs.com'

    # Bucket and Object
    bucket_name = "examplebucket"
    object_key = "test.bak"

    # Full path of the local file to upload.
    # Windows example: r'D:\localpath\examplefile.txt'  (note the r at the beginning)
    # macOS/Linux example: '/Users/test/examplefile.txt'
    file_path = r"D:\oss\test.bak"

    # Sharding and concurrency
    part_size = 1 * 1024 * 1024  # Default is 1 MB; OSS requires a minimum part size of 100 KB
    parallel_num = 4

    # Resumable upload directory (pass None to disable; specify a writable directory)
    checkpoint_dir = str(Path.cwd() / ".oss_checkpoints")
    # =================== End of parameters ===================

    print("Script execution starts...")
    try:
        client = get_client_from_env(region=region, endpoint=endpoint)
        # If resumable upload is enabled, make sure the directory exists
        if checkpoint_dir:
            Path(checkpoint_dir).mkdir(parents=True, exist_ok=True)

        resumable_upload_file_v2(
            client=client,
            bucket_name=bucket_name,
            object_key=object_key,
            file_path=file_path,
            part_size=part_size,
            parallel_num=parallel_num,
            checkpoint_dir=checkpoint_dir,
        )
    except FileNotFoundError as e:
        print(e)
    except oss_ex.ServiceError as e:
        # Error returned by the OSS server
        print("\nAn OSS server-side error occurred.")
        print(f"HTTP Status: {getattr(e, 'status_code', 'N/A')}")
        print(f"Error Code: {getattr(e, 'code', 'N/A')}")
        print(f"Message: {getattr(e, 'message', 'N/A')}")
        print(f"Request ID: {getattr(e, 'request_id', 'N/A')}")
        print(f"Endpoint: {getattr(e, 'request_target', 'N/A')}")
    except oss_ex.BaseError as e:
        # SDK local/serialization/deserialization/credential errors
        print("\nAn OSS SDK client-side error occurred.")
        print(str(e))
    except Exception as e:
        print(f"\nAn unknown error occurred: {e}")


if __name__ == "__main__":
    main()

Step 3: Run the migration script

  1. Download the SQL Server migration script.

  2. Extract the package. To view the required parameters, run:

    ParameterDescription
    access_key_idAccessKey ID of the Alibaba Cloud account that owns the destination RDS instance
    access_key_secretAccessKey secret of that account
    rds_instance_idID of the destination ApsaraDB RDS instance
    oss_endpointEndpoint of the OSS bucket containing the backup files
    oss_bucketName of the OSS bucket
    directoryFolder in the bucket where backup files are stored. Use / for the root directory.
    python ~/Downloads/RDSSQLCreateMigrateTasksBatchly.py -h

    The command syntax is:

    RDSSQLCreateMigrateTasksBatchly.py -k <access_key_id> -s <access_key_secret> -i <rds_instance_id> -e <oss_endpoint> -b <oss_bucket> -d <directory>
  3. Run the script. The following example migrates all eligible backup files from the Migrationdata folder in the testdatabucket bucket to RDS instance rm-2zesz5774ud8s****:

    python ~/Downloads/RDSSQLCreateMigrateTasksBatchly.py -k yourAccessKeyID -s yourAccessKeySecret -i rm-2zesz5774ud8s**** -e oss-cn-beijing.aliyuncs.com -b testdatabucket -d Migrationdata

Step 4: Monitor migration progress

Select the tab for your SQL Server version.

SQL Server 2012 and later

In the left navigation pane of your ApsaraDB RDS instance, click Backup and Restoration. On the Cloud Migration Records of Backup Data tab, view migration records including task status, start time, and end time. By default, the last week of records is shown. Adjust the time range as needed.

image

Note

If Task Status is Failed, check the Task Description or click View File Details to identify the cause. After fixing the issue, run the migration script again.

SQL Server 2008 R2

In the left navigation pane, click Data Migration To Cloud. Find the target migration task to view its progress.

Note

If Task Status is Failed, check the Task Description or click View File Details to identify the cause. After fixing the issue, run the migration script again.

Troubleshooting

Script and API errors

Error messageCauseSolution
HTTP Status: 404 Error:InvalidAccessKeyId.NotFound Specified access key is not found.Incorrect AccessKey IDEnter the correct AccessKey ID and AccessKey secret.
HTTP Status: 400 Error:IncompleteSignature The request signature does not conform to Aliyun standards.Incorrect AccessKey secretEnter the correct AccessKey secret.
RDS engine doesn't support, this is only for RDS SQL Server engine.The destination instance is not running SQL ServerUse an ApsaraDB RDS for SQL Server instance as the destination.
Couldn't find specify RDS [XXX].The RDS instance ID does not existVerify the instance ID is correct.
{'status': -2, ..., 'Failed to establish a new connection'}Incorrect OSS endpointVerify the OSS endpoint.
{'status': 404, ..., 'The specified bucket does not exist.'}OSS bucket does not existVerify the bucket name.
There is no backup file on OSS Bucket [xxxxxx] under [xxxxxxxxx] folderThe folder does not exist or contains no eligible backup filesVerify that the folder path is correct and contains .bak files.
Warning!!!!!, [autotest_2005_ent_broken_full_dbcc_failed.bak] is not backup file, filtered.Backup file does not follow the naming conventionRename files to DatabaseName_BackupType_BackupTime.bak — for example, Testdb_FULL_20180518153544.bak.
HTTP Status: 403 Error:Forbidden.RAM ... AccessDeniedRAM user lacks required permissionsGrant the RAM user the AliyunOSSFullAccess and AliyunRDSFullAccess permissions.
OPENAPI Response Error !!!!! : HTTP Status: <Http Status Code> Error:<Error>OpenAPI returned an errorIdentify the cause using the error code and message below.

OpenAPI error codes

HTTP status codeErrorDescriptionResolution
403InvalidDBNameThe database name is invalid (system database names are not allowed).Use a valid database name.
403IncorrectDBInstanceStateThe RDS instance is in an invalid state (for example, it is still being created).Wait until the instance status is Running.
400IncorrectDBInstanceTypeThe destination database engine is not SQL Server.Use an ApsaraDB RDS for SQL Server instance.
400IncorrectDBInstanceLockModeThe database is in an invalid lock state.Check and resolve the lock state.
400InvalidDBName.NotFoundFor SQL Server 2008 R2: the database does not exist on the destination. For SQL Server 2012 and later: a database with the same name already exists on the destination.For SQL Server 2008 R2, create a database with the same name on the destination instance first. For SQL Server 2012 and later, ensure that no database with the same name exists on the destination instance.
400IncorrectDBTypeThe database type does not support this operation.Verify the database type.
400IncorrectDBStateThe database is in an invalid state (for example, a migration task is already in progress).Wait for the current task to complete.
400UploadLimitExceededExceeded the daily migration limit per database (maximum 20 per day).Wait until the next day.
400ConcurrentTaskExceededExceeded the daily migration limit per instance (maximum 500 per day).Wait until the next day.
400IncorrectFileExtensionThe backup file extension is invalid.Use .bak files only.
400InvalidOssUrlThe OSS download URL is unavailable.Verify the OSS endpoint and bucket configuration.
400BakFileSizeExceededThe backup file exceeds the maximum size (3 TB).Split the backup or use an alternative migration approach.
400FileSizeExceededRestoring the backup would exceed the instance's storage capacity.Upgrade the instance specifications before retrying.

API reference

APIDescription
CreateMigrateTaskCreates a data migration task that restores a backup file from OSS to an ApsaraDB RDS for SQL Server instance
CreateOnlineDatabaseTaskOpens the database of an ApsaraDB RDS for SQL Server data migration task
DescribeMigrateTasksQueries the list of data migration tasks for an ApsaraDB RDS for SQL Server instance
DescribeOssDownloadsQueries the file details of an ApsaraDB RDS for SQL Server data migration task