The fundamental difference between migrating data to an on-premise SQL Server and migrating it to Azure SQL Database is file access. An on-premise SQL Server is a Windows machine on your network — you can give its service account access to a local folder, and BULK INSERT can read directly from disk. Azure SQL is a managed service running in Microsoft's data centers. Its compute engine has no access to your local file system, and even if you try to run BULK INSERT with a local path, the statement will fail immediately with a path-not-found error.
Every migration technique covered in this guide solves this problem differently. Understanding which bridge each tool uses — and what that means for file size limits, authentication, and repeatability — is more useful than a list of steps.
Before You Start: Two Blockers That Affect Every Method
These two issues cause the majority of failed Azure SQL import attempts, regardless of which tool you use. Resolving them before starting any migration saves significant troubleshooting time.
Azure SQL Database blocks all inbound connections by default. To connect from any external tool — SSMS, Azure Data Studio, ADF, a script — you must add your IP address to the server-level firewall in the Azure Portal: SQL servers → [your server] → Networking → Add your client IP. If you are in an office with a dynamic IP or behind a corporate proxy, the IP displayed in the Portal may differ from the one Azure sees. The easiest test: try to connect from SSMS. If it times out or returns "Login failed" before even prompting for credentials, the firewall is blocking the connection.
Azure SQL supports two authentication modes: SQL Authentication (username and password stored in the database) and Azure Active Directory (Azure AD) authentication. By default, newer Azure SQL servers are created with Azure AD-only authentication and no SQL login. If your tool or script tries to connect with a SQL username and password and receives "Cannot open server requested by the login," the server may have SQL Authentication disabled. Check under SQL servers → [your server] → Azure Active Directory → and note whether "Support only Microsoft Entra authentication" is toggled on. Enable SQL Authentication if you need it, or use an Azure AD account.
Method 1: Azure Data Studio with the SQL Server Import Extension
Azure Data Studio is a cross-platform database client (Windows, Mac, Linux) that Microsoft positions as the modern replacement for SSMS for day-to-day query and management work. The "SQL Server Import" extension adds a CSV-to-table wizard that can connect to Azure SQL and upload data directly from a local file. It is the fastest path for a one-time migration of a file that fits comfortably in memory.
The extension streams the CSV from your machine to Azure SQL over the TDS (Tabular Data Stream) protocol — the same connection used for normal queries. This means the transfer speed is limited by your upload bandwidth and the connection latency to the Azure region hosting your database. For files under a few hundred thousand rows, this is not a noticeable constraint. For files in the millions, this method becomes impractical.
SQL Server Import extension — key configuration points
| Step | What to do | Common mistake |
|---|---|---|
| Install the extension | Extensions panel → search "SQL Server Import" → Install | The extension is not bundled — it must be installed separately even on a fresh ADS install |
| Connect to Azure SQL | New Connection → enter server FQDN (e.g., myserver.database.windows.net), database, and credentials | Using the server name without the .database.windows.net suffix causes a connection failure |
| Select the destination database | Right-click the database in the Connections pane → Import Wizard | Right-clicking the server (not the database) opens a different context menu without the import option |
| Column type preview | The wizard samples the CSV and suggests types — review every column before accepting | Sparse columns or columns with leading nulls get incorrect type suggestions; override string columns to NVARCHAR(MAX) when uncertain |
| New table vs existing table | The wizard creates a new table by default — if the table exists, you must select it explicitly | Accepting the default creates a duplicate table with a generated name |
Method 2: Azure Blob Storage + BULK INSERT / OPENROWSET
For large files or for any situation where you want a reliable, repeatable, high-performance import, the correct pattern is to stage the CSV in Azure Blob Storage first, then have Azure SQL pull it from there. Because both Blob Storage and Azure SQL live in Azure's network, the actual data transfer happens cloud-to-cloud — your local internet connection is only involved in the initial upload to Blob Storage, which you can do once and retry if it drops.
Once the file is in Blob Storage, Azure SQL can read it using BULK INSERT with a Shared Access Signature (SAS) URL, or using OPENROWSET with the same credential. The BULK INSERT option table applies here — TABLOCK, BATCHSIZE, FIRSTROW, and FORMAT = 'CSV' all work the same way in Azure SQL as in on-premise SQL Server. The only difference is the file path: instead of a Windows folder path, you provide the Blob Storage URL.
Upload the CSV to Azure Blob Storage
Use Azure Storage Explorer (a free desktop tool) or the Azure Portal's Storage Browser to upload the file to a container. Create a container dedicated to imports (e.g., "csv-imports") so it's easy to manage access separately from other storage. Storage Explorer can upload files of any size and handles interruptions — it resumes where it left off.
Create a Shared Access Signature (SAS) token
A SAS token is a time-limited, permission-scoped credential that Azure SQL uses to authenticate against Blob Storage without requiring your full account key. In Azure Portal → Storage account → Containers → [container] → Shared access tokens → set Read permission and an expiry that covers the import window. Copy the SAS URL — it includes both the blob path and the credential.
Create a DATABASE SCOPED CREDENTIAL
In Azure SQL, run a T-SQL statement to store the SAS token as a database-scoped credential. This keeps the credential inside the database rather than embedded in the query text. Name the credential after the blob service URL (e.g., https://[account].blob.core.windows.net). The credential is then referenced by BULK INSERT or OPENROWSET when accessing that storage account.
Run BULK INSERT referencing the Blob Storage URL
The BULK INSERT statement targets the Blob Storage URL instead of a local path. All the standard performance options apply: FORMAT, FIRSTROW, TABLOCK, BATCHSIZE, ERRORFILE. The ERRORFILE path must also be a Blob Storage URL when running in Azure SQL — you cannot redirect errors to a local drive.
Keep the Blob Storage account in the same Azure region as the database
Blob Storage in the same Azure region as your Azure SQL server transfers data over Microsoft's internal network backbone — no egress charges and near-LAN speeds. Cross-region transfers incur both egress charges and latency. When creating the Storage account, select the same region as your Azure SQL server (visible in the Azure Portal under SQL databases → [your db] → Overview → Location).
Method 3: Azure Data Factory
Azure Data Factory is Microsoft's cloud ETL service — the managed cloud equivalent of SSIS for teams that don't want to manage SSIS infrastructure. ADF pipelines are configured through a browser-based designer and run on Microsoft-managed integration runtimes, with no local tooling to install beyond the Azure Portal.
For CSV-to-Azure-SQL specifically, ADF's Copy Data activity reads from a source (Blob Storage, SFTP, HTTP, local file via a Self-Hosted Integration Runtime) and writes to a destination (Azure SQL). The Copy Data wizard handles connection configuration, schema mapping, and type conversion through a guided interface. The result is a reusable pipeline that can be triggered on a schedule, by an event (e.g., a new file landing in Blob Storage), or via REST API.
ADF Copy Data activity — key configuration decisions
| Decision point | Option | When to use it |
|---|---|---|
| Integration runtime | Azure IR (default) | Source data is already in Azure (Blob Storage, SFTP, HTTP endpoint) |
| Integration runtime | Self-Hosted IR | Source data is on a local machine or behind a corporate firewall — a small agent is installed on-premise |
| Source linked service | Azure Blob Storage | File is uploaded to Blob Storage first — fastest and most reliable path |
| Source linked service | HTTP dataset | CSV is hosted at a public URL (e.g., a data feed from a vendor) — ADF fetches it on each trigger |
| Copy method | Bulk insert (default) | Maximum throughput — ADF uses BULK INSERT internally for Azure SQL destinations |
| Copy method | Upsert | When re-running the pipeline should update existing rows rather than inserting duplicates — requires a key column |
| Trigger type | Schedule | Fixed frequency (daily, hourly) — configured in trigger settings |
| Trigger type | Storage event | Runs automatically when a new blob is created in the source container — no fixed schedule needed |
| Fault tolerance | Skip incompatible rows | Allows the pipeline to continue past type-mismatch errors and log rejected rows to a separate blob |
ADF vs SSIS: the managed vs self-managed tradeoff
SSIS requires you to manage the server or Azure-SSIS Integration Runtime that runs packages. ADF's Azure Integration Runtime is fully managed — Microsoft scales it, patches it, and makes it available without any infrastructure management on your side. ADF is the better choice for new cloud-native pipelines. SSIS remains relevant when migrating existing SSIS packages to the cloud (Azure-SSIS IR can run .dtsx packages without modification) or when the pipeline requires components that don't have ADF equivalents.
Method 4: SSMS Import and Export Wizard
The SSMS Import and Export Wizard works against Azure SQL in the same way it works against on-premise SQL Server — you connect via a standard connection string, select the source (a local CSV), and run the wizard. The data travels row-by-row over the same TDS connection used for normal queries, from your local machine across the internet to Azure SQL.
This method is familiar and requires no additional tools beyond SSMS, but the row-by-row transfer mechanism means it is fundamentally slower than Blob Storage + BULK INSERT for large files. At 10,000 rows per second (a generous estimate over a typical business internet connection), a 5-million-row file takes over 8 minutes. The same file loaded from Blob Storage via BULK INSERT typically lands in under 2 minutes. For one-time migrations of small files where you already have SSMS open, the wizard is acceptable. For any recurring import or for files over a few hundred thousand rows, use a different method.
Choosing the Right Tool
| Situation | Best tool | Why |
|---|---|---|
| One-time import, file under 500k rows | Azure Data Studio + SQL Server Import extension | Fastest setup, no extra Azure services needed, type detection built in |
| One-time import, file over 100MB | Blob Storage + BULK INSERT | Avoids timeout risk, cloud-to-cloud transfer, no bandwidth dependency |
| Recurring scheduled import from a fixed location | Azure Data Factory (Schedule trigger) | Managed infrastructure, built-in retry logic, monitoring in the Azure Portal |
| Event-driven import (new file → trigger load) | Azure Data Factory (Storage event trigger) | Near-real-time processing without polling on a fixed schedule |
| Import with on-the-fly transformation or enrichment | Azure Data Factory (Mapping Data Flows) | Visual column mapping, expression-based transformation, no external compute needed |
| Familiar with SSMS, small file, one-time task | SSMS Import Wizard | No additional setup, existing tooling, acceptable for small volumes |
| Migrating from on-premise SSIS packages | Azure-SSIS Integration Runtime in ADF | Runs existing .dtsx packages unchanged in the cloud without redesign |
Azure Blob Storage: The Common Thread
Three of the four methods above either require or work best with Azure Blob Storage as an intermediate staging layer. Blob Storage in Azure is the equivalent of Amazon S3 — it is the standard object store for unstructured data, and it is deeply integrated with every Azure data service. ADF's most reliable source connectors target Blob Storage. BULK INSERT from Azure SQL targets Blob Storage URLs. Azure Synapse, Azure Databricks, and Azure Machine Learning all read from Blob Storage natively.
Getting comfortable with Blob Storage — understanding containers, access tiers (Hot vs Cool vs Archive), SAS tokens, and lifecycle policies — is the single highest-leverage skill for anyone working with data in Azure long-term. If you expect to migrate data to Azure SQL more than once, set up a dedicated Storage account for it now. The time investment is small and it removes the file-access constraint from every future migration.
Blob Storage concepts every Azure SQL user should know
| Concept | What it is | Why it matters for CSV import |
|---|---|---|
| Container | A logical grouping of blobs inside a Storage account, similar to a top-level folder | Create a separate container for import staging so you can set SAS permissions at the container level without exposing other blobs |
| SAS token | A time-limited, permission-scoped URL that grants access to a specific blob or container | Used as the credential in DATABASE SCOPED CREDENTIAL so Azure SQL can authenticate against Blob Storage without your account key |
| Access tier | Hot (frequent access), Cool (infrequent), Archive (rare) — affects cost per GB and retrieval latency | Use Hot tier for the import container — Cool and Archive tiers have retrieval delays that cause BULK INSERT timeouts |
| Soft delete | A setting that retains deleted blobs for a configurable number of days before permanent removal | Enable it on the import container to recover accidentally deleted CSV files before the next import run |
| Lifecycle policy | Rules that automatically move or delete blobs after a specified number of days | Set a policy to auto-delete blobs from the import container after 30 days to prevent unbounded storage growth |
SQL Server import reference
BULK INSERT in T-SQL: Step-by-Step
Every WITH clause option, the 5-condition performance checklist, and the ERRORFILE behavior explained.
CSV Ingestion with SSIS
Data Flow components, type conversion reference, error row redirection, and the Foreach Loop folder pattern.
Automating CSV Imports with PowerShell
Invoke-Sqlcmd, SQL Server Agent job configuration, two-account permissions matrix.
Minimal Logging for Maximum Speed
The five conditions that enable minimal logging in SQL Server and Azure SQL.
All 5 SQL Server CSV Import Methods
Full comparison of BULK INSERT, BCP, OPENROWSET, the Import Wizard, and PowerShell.
Automated CSV ingestion for Azure SQL, without the configuration
Elvity handles Blob Storage staging, SAS credentials, BULK INSERT configuration, and scheduling — without manual pipeline setup in ADF or SSMS.