Updated October 16, 2026. 

Salesforce has no on-premises edition, so "on-premise Salesforce" always means the same thing in practice: an on-premises database (SQL Server, MySQL, PostgreSQL, Oracle or an ERP's database) that has to feed Salesforce, or be fed by it, while the CRM itself stays in Salesforce's cloud. There are four ways to do that. Salesforce Data Loader for a one-off migration. Salesforce Connect if you only need to see external records inside Salesforce without copying them. A do-it-yourself pipeline on the Bulk API if you have engineers to keep it running. Or a managed integration platform that connects to the database behind your firewall, maps and upserts the records, and runs on a schedule or on change data capture.

This guide explains when each fits, then walks through a production sync step by step, using Integrate.io as the worked example because it is the tool we build. The failure points in section five apply whichever route you take.

Key takeaways:

  • Decide the direction and the key before the tool. Every reliable sync writes your database primary key into a Salesforce External ID field and upserts on it. Field mapping comes second.
  • Salesforce's Bulk API 2.0 allows 150 million records per rolling 24 hours in batches of up to 10,000 records, which is plenty for a migration but means you design loads in batches, not row by row.
  • Reaching a database behind a firewall is a networking decision (IP allowlist, SSH tunnel or an agent), not a Salesforce one. Settle it with IT first.
  • Four things break syncs after go-live: 15- versus 18-character Salesforce IDs, schema changes on either side, deletes, and API limits. Plan for each before the backfill.
  • For a one-off load, Data Loader is free. For an ongoing sync that non-engineers can own, a managed pipeline costs money and saves the maintenance.

Four Ways to Connect an On-Premise Database to Salesforce

Method Best for How it works Limits to know Cost
Salesforce Data Loader One-time migration or an occasional manual load Export tables to CSV, map columns, insert or upsert through Salesforce's free desktop client Salesforce documents it for 50,000 to 5 million records per load; manual, so no scheduling or change capture Free
Salesforce Connect Showing external records inside Salesforce without copying them External objects over an OData 2.0 or 4.0 endpoint; Salesforce fetches rows live by web-service callout Data is not stored in Salesforce (no reports on history, limited automation); default pages of 500 rows, 2,000 max; hourly callout limits by edition; you must expose the database as OData Add-on licence
DIY pipeline (CDC + Bulk API 2.0) Engineering teams that want full control Enable change capture on the database, read changes, transform, upsert through Bulk API 2.0 or the REST API; Salesforce Change Data Capture for the return direction Bulk API 2.0: 150M records per rolling 24 hours, 150 MB per file, 10,000-record batches; you own retries, schema changes and monitoring Engineering time
Managed integration platform Ongoing bidirectional sync owned by ops or RevOps, with compliance requirements Connects to the database behind the firewall, maps fields visually, upserts on external IDs through Bulk API 2.0, runs on a schedule or CDC, alerts on failures Platform pricing; some vendors meter by rows or events Integrate.io $1,999/month flat; others usage-based or quote

Two rules of thumb. If the records have to live in Salesforce (for reports, automation, Agentforce), you are copying data, so it is Data Loader, DIY or a platform. If users only need to look up a record that lives in the database, Salesforce Connect avoids the copy and the sync. And if the integration has to keep running after the person who built it moves on, pick the option with the least custom code.

Before You Build: Keys, Direction and Network Access

1. Decide the key

Create a custom External ID field on each Salesforce object you will load (Account, Contact, Opportunity, or a custom object) and write the database primary key into it. Mark it unique. Every subsequent write is then an upsert on that field: Salesforce updates the record if the key exists and inserts if it does not, so re-running a job never creates duplicates. For child records, load parents first and reference them by the parent's external ID rather than by Salesforce ID. Our guide to matching Salesforce records with external IDs covers the edge cases.

If data flows back from Salesforce to the database, store the Salesforce record ID in the database too, and store the 18-character form. The 15-character ID is case-sensitive, and a SQL Server column with a case-insensitive collation will treat two different 15-character IDs as the same value.

2. Decide the direction per object

Most syncs are not symmetrical. Accounts might be mastered in the ERP database and pushed to Salesforce; Opportunities are mastered in Salesforce and pulled back for finance. Write down the system of record for each object. Bidirectional sync of the same field is possible but needs conflict rules (last write wins, or source wins), so keep it to the fields that genuinely change in both places.

3. Settle network access with IT

Salesforce lives in the cloud; your database does not. A cloud integration platform reaches it one of three ways: you allow-list the platform's IP addresses on the database firewall, you open an SSH tunnel (or reverse tunnel) to a bastion host, or you install the vendor's agent inside the network. Integrate.io supports the first two for SQL Server, MySQL and PostgreSQL. A DIY pipeline running inside the network only needs outbound HTTPS to Salesforce. Agree the method, the service account and its minimum permissions (read on source tables, write on the staging table if any) before anyone builds a pipeline.

4. Profile the data

Run the checks that will otherwise fail at load time: required Salesforce fields with no source value, picklist values that do not exist in Salesforce, text longer than the field length, phone and date formats, and duplicate keys in the source. Fix them in the transformation, not by hand in a CSV.

Step by Step: A Production Sync With Integrate.io

The steps below describe a scheduled or change-driven sync from an on-premises SQL Server to Salesforce, with Salesforce changes flowing back to the warehouse. The same flow works for MySQL, PostgreSQL and Oracle sources; see the pairing pages for SQL Server to Salesforce, MySQL to Salesforce and PostgreSQL to Salesforce, and our separate on-premise MySQL to Salesforce guide.

Step 1: Connect the database

Create a database connection with the host, port, database name and the service account from the preparation step. Choose direct access if IT has allow-listed Integrate.io's IP addresses, or SSH tunnel if they prefer a bastion. Test the connection and confirm you can see the source tables.

Step 2: Connect Salesforce

Authorise an integration user in Salesforce (a dedicated user with API access and field-level permissions on the target objects, not a person's login). Integrate.io uses the Salesforce REST API for real-time operations and Bulk API 2.0 for high-volume loads, and lets you set the batch size per job.

Step 3: Build the pipeline and map keys first

In the visual pipeline editor, add the database source, select the tables or write the extraction query, and add a Salesforce destination per object. Map the primary key to the External ID field before any other field, set the write mode to upsert on that field, then map the rest. Use the built-in transformation steps (220+ of them, with SQL or Python for edge cases) to standardise formats, translate picklist values, split or join names and addresses, and drop rows that fail validation into a separate error output instead of failing the whole batch. For parent-child objects, build the parent pipeline first and reference parents by external ID in the child pipeline.

Step 4: Run the backfill

Load historical data once before you turn on incremental sync. For large Salesforce objects on the return direction, turn on PK chunking, which splits a Bulk API query into parallel chunks of 100,000 records by default (configurable up to 250,000). When the backfill finishes, reconcile: row counts per object, a sample of records compared field by field, and a check that no External ID is null.

Step 5: Turn on incremental sync

Schedule the pipeline (every 15 minutes, hourly, daily, or a custom cadence) or run it on change data capture so only inserts, updates and deletes since the last run are processed. Integrate.io's CDC replicates database changes on 60-second cycles with self-healing pipelines and automatic schema mapping, and Salesforce's own Change Data Capture events can stream Salesforce-side changes back. See change data capture in Salesforce for the Salesforce side.

Step 6: Monitor

Set alerts on failed runs, row counts outside the expected range and schema changes, delivered to email, Slack, Microsoft Teams, PagerDuty or a webhook. Review the error output weekly for the first month; most of what lands there is a picklist value or a field length that the mapping needs to handle.

Security and compliance: Integrate.io is SOC 2, HIPAA, GDPR and CCPA compliant, with field-level encryption and masking functions for PII in flight. DPD UK and the Boston Red Sox run their Salesforce data syncs on the platform.

Five Things That Break Database-to-Salesforce Syncs

  1. IDs that do not match. No External ID, or a non-unique one, produces duplicates on the second run. Store the 18-character Salesforce ID in the database; if you must store the 15-character form in SQL Server, use a case-sensitive or binary collation on that column.
  2. Schema changes. A new custom field in Salesforce or a renamed column in the database. Decide the policy (ignore, alert, auto-map) and make sure the tool enforces it. Integrate.io's automatic schema mapping handles source changes; new Salesforce fields still need a mapping decision.
  3. Deletes. A row deleted in the database will not delete the Salesforce record unless you send the delete. Most teams map deletes to a status field (soft delete) on both sides rather than hard-deleting CRM history.
  4. API limits. Bulk API 2.0 allows 150 million records per rolling 24 hours and 150 MB per file. A chatty REST-based sync can exhaust the org's daily API request allocation; batch writes and use CDC rather than polling every minute.
  5. Security review failures. A pipeline that uses a person's login, writes PII without masking, or has no audit trail will not pass compliance review. Use an integration user, mask or encrypt sensitive fields in the transformation, and keep run logs.

Other Tools Worth Knowing

  • MuleSoft Anypoint Platform (owned by Salesforce): API-led integration with a Database connector and the DataWeave transformation language. Powerful, developer-run, quote-based pricing. See our MuleSoft vs. Integrate.io comparison.
  • Boomi: visual iPaaS with suggested field mappings, good for ERP-to-CRM process integration; committed editions by quote, 30-day trial.
  • CData DBAmp: installs on the SQL Server host and exposes Salesforce as a linked server, so DBAs query it in T-SQL, keep local mirror tables and write back with upserts on external IDs. No middleware, but SQL Server only.
  • Skyvia: low-cost cloud integration with a free plan, suited to small scheduled syncs.
  • SSIS with a Salesforce connector: works if you already run SSIS, but connector licences, API changes and on-prem networking make it a maintenance item.

For a ranked comparison, see Salesforce middleware integration tools and the top Salesforce ETL tools. If your source is files rather than a database, see SFTP to Salesforce.

FAQs

Can Salesforce be installed on-premise?

No. Salesforce is a multi-tenant cloud service with no on-premises edition. "Salesforce on-premise integration" means connecting Salesforce to systems that run on your own servers, which is what this guide covers.

How do I connect SQL Server to Salesforce?

Three realistic routes. For a one-off load, export to CSV and use Data Loader. For a DIY sync, enable change data capture or change tracking on the SQL Server tables, write the key into a Salesforce External ID field, and upsert through Bulk API 2.0 from a job inside your network. For an ongoing sync owned by non-engineers, use an integration platform: connect SQL Server by IP allowlist or SSH tunnel, map keys and fields visually, and schedule it or run it on CDC. The SQL Server to Salesforce page shows the Integrate.io version.

How do I migrate data from SQL Server to Salesforce?

Clean and de-duplicate in SQL Server first, create External ID fields on the target objects, load parents before children, run the migration as upserts in batches through Bulk API 2.0 (Data Loader or a pipeline tool), then reconcile counts and spot-check records. Keep the mapping document; it becomes the specification for the ongoing sync.

Does a database-to-Salesforce sync use up my Salesforce API limits?

Yes. Bulk API 2.0 ingest is limited to 150 million records per rolling 24 hours (15,000 batches of up to 10,000 records) and 150 MB per file, and REST calls count against the org's daily API request allocation. Batch writes, use change capture instead of frequent full polls, and schedule large loads off-peak.

Should I use Salesforce Connect instead of syncing?

Use Salesforce Connect when users only need to view or look up external records inside Salesforce and the data can stay in the database. It reads live through OData callouts, so there is no copy to keep in sync, but the data is not available for standard reports on history, most automation, or offline use, and the database has to be exposed as an OData service. If the records must exist in Salesforce, sync them. See our introduction to Salesforce Connect.

Can the sync run in both directions?

Yes, but define a system of record per object and per field. Integrate.io handles standard and custom objects in both directions, upserting into Salesforce by External ID and pulling Salesforce changes out through the Bulk API or Change Data Capture. Keep truly bidirectional fields to a minimum and set a conflict rule for them.

How do I handle deleted records?

Decide explicitly. Hard-deleting CRM records from a database delete is rarely what the business wants; map deletes to a status or an "inactive" flag on both sides and let the sync update it. If you do propagate hard deletes, make sure the pipeline sends them (a scheduled upsert never will).

Related guides: Salesforce REST API integration, Salesforce Data Loader, the Salesforce database explained, why you should ETL your Salesforce data and data transformation explained.

Integrate.io: Delivering Speed to Data
Reduce time from source to ready data with automated pipelines, fixed-fee pricing, and white-glove support
Integrate.io