Last updated
One way: SharePoint stays the system of record, and SPSync keeps a read-only copy of your lists current in Azure Database for MySQL.
Status: Shipped · product: SPSync for Relational Databases
Azure Database for MySQL Flexible Server turns TLS on for new servers, and getting that one setting right is most of the work. After that, SPSync writes SharePoint lists as MySQL tables that an App Service app, a Function, Metabase or Power BI’s MySQL connector reads as it would any other database.
TLS, sign-in and the network path
Download the root certificate Microsoft publishes for Flexible Server, DigiCert Global
Root G2 at the time of writing, and add ssl_ca=/path/to/the-certificate.pem to the
connection string. The MySQL driver SPSync uses treats that as “require TLS and verify
the server”. Do not also add ssl_verify_identity=true; with this driver it discards the
certificate path and turns verification off.
Sign-in is a MySQL username and password, read from the environment variable that holds
the connection string. Flexible Server accepts a plain username. Older Single Server
instances often expect user@servername. Microsoft Entra authentication is not supported
today.
Open one network path before the first run:
- a firewall rule for the address the sync runs from, if the server allows public access;
- or a host inside the VNet, if the server uses private access.
Test it from wherever the sync will run, whether that is a desktop, SPSync in your Azure or a build agent, because an admin’s own laptop often has a path the sync host lacks.
Tables and types
An approved-vendor list with a Category lookup, a Buyer person column and a
multi-choice Regions column becomes proc_vendors, keyed on the SharePoint item ID,
with category_id and category_value, a buyer_user_id that joins to sp_users, and a
proc_vendors__regions child table. GUIDs and shorter text columns are bounded
VARCHAR(n), so you can put a unique index on them. Long text stays TEXT and is not
indexed for you. Table and column names are capped at 64 characters, and SPSync shortens
longer SharePoint names to fit.
A new SharePoint column appears on the next run, a removed one stays, and a retyped column
gets a _v2 column alongside.
| Title | Client lookup | Tags multi-choice | Owner person | Due |
|---|---|---|---|---|
| Riverside | Acme Ltd | Design; Build | Ada Lovelace | 2026-11-30 |
| Harbour | Borealis plc | Build | Alan Turing | 2027-02-14 |
then sync
- id
- title
- client_id → clients.id
- owner_id → sp_users.id
- due
- is_deleted soft delete
- sp_modified
- id
- title
- …
- project_id
- tag
One row per value: Riverside has two.
- id
- display_name
One users table shared by every list.
Uses on Azure
An app’s read model. An App Service or Function that reads reference data through Graph can query the server instead; see a read replica for internal apps.
Dashboards. Metabase or Grafana connect with their MySQL drivers; see Tableau, Looker, Metabase and Grafana on SharePoint data.
Master data for integrations. Cost centres and product codes become tables Logic Apps can query; see reference and master data from SharePoint.
A move off SharePoint lists. The replica gives an application something to cut over to; see migrating list data off SharePoint.
Steps
- Start with delegated sign-in, or ask a SharePoint admin to approve
Sites.Selectedon the sites so the sync can run unattended. - Create a MySQL user that can create tables in the target database.
- Store the connection string, with
ssl_ca, in an environment variable. - Choose lists or a whole site and run; the first run creates the schema.
- Set a schedule. Later runs read changes only, with a reconcile, weekly by default.
The server’s compute tier affects how long the first full load of a large list takes far more than it affects later runs.
Desktop, Azure or command line
All three editions run the same engine, write the same tables and use the same licence key, so the choice comes down to who looks after the sync.
Desktop app
For macOS and Windows. Sign in with Microsoft, tick the lists, choose a database and sync from your own machine on the schedule you set. Delegated sign-in needs no admin unless your tenant requires admin consent for apps.
In your Azure
SPSync in your Azure, a managed application for your own subscription, is deployed with you on a call while the Marketplace listing is prepared. Once deployed it is always on, so the sync keeps running with every laptop closed.
Command line
Every replication is a YAML file you can review and commit. Run it from a server, a container or a CI pipeline, and re-run it safely any time.
Frequently asked questions
Is this the same as the MySQL destination?
Yes, it is the MySQL destination pointed at Microsoft's managed service. This page covers the Azure parts: TLS, sign-in and networking.
How does SPSync authenticate to Azure Database for MySQL?
With a MySQL username and password over TLS. Microsoft Entra authentication is not supported today.
Which certificate setting does the connection string need?
Only ssl_ca, set to the path of the root certificate Azure publishes for Flexible Server. That one setting makes TLS required and verifies the server. Adding ssl_verify_identity as well switches verification off in the MySQL driver SPSync uses, so leave it out.
Can several SharePoint sites replicate into one server?
Yes. Each site's tables get their own prefix, so several sites share a database without name clashes.
Talk to us about Azure Database for MySQL
SPSync is licensed per installation and per target family, with Standard Support included. Tell us which targets you need and how many machines, and we will size it with you. See how licensing works.
Set it up
Sign in to SharePoint with the SharePoint connection guide, then follow the MySQL and MariaDB setup guide to create the database user and open the connection for Azure Database for MySQL. If the connection test fails, the troubleshooting guide lists the errors people hit and what fixes them.
Script it
Everything you can click, you can script. The CLI, YAML config and automation below reproduce this scenario exactly. See the CLI reference.
spsync auth login --client-id 00000000-0000-0000-0000-000000000000
spsync export-config --output replication.yaml --pipeline-name azure_database_for_mysql --prefix azure_database_for_mysql --destination-kind mysql --connection-string-env SPSYNC_DB_CONNECTION --dataset-name azure_database_for_mysql --client-id 00000000-0000-0000-0000-000000000000 --site-url https://contoso.sharepoint.com/sites/example --all-lists
spsync doctor replication.yaml
spsync run replication.yaml pipeline_name: azure_database_for_mysql
prefix: azure_database_for_mysql
auth:
mode: delegated
client_id: 00000000-0000-0000-0000-000000000000
tenant_id: common
destination:
kind: mysql
connection_string_env: SPSYNC_DB_CONNECTION
dataset_name: azure_database_for_mysql
scopes:
- site_url: https://contoso.sharepoint.com/sites/example
mode: entire_site
reconcile_interval_days: 7
create_reporting_views: false
Cron (MySQL nightly):
# every night at 02:00
0 2 * * * cd /opt/spsync && SPSYNC_DB_CONNECTION="$(cat /etc/spsync/db.env)" uv run spsync run replication.yaml >> /var/log/spsync/run.log 2>&1 GitHub Actions:
# .github/workflows/spsync-run.yml
name: SPSync
on:
schedule:
- cron: "0 2 * * *"
workflow_dispatch: {}
jobs:
run:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v3
- run: uv sync
- run: uv run spsync run replication.yaml
env:
SPSYNC_DB_CONNECTION: ${{ secrets.SPSYNC_DB_CONNECTION }}
SPSYNC_LICENCE_KEY: ${{ secrets.SPSYNC_LICENCE_KEY }} Azure DevOps:
# azure-pipelines.yml
schedules:
- cron: "0 2 * * *"
branches: { include: [main] }
always: true
steps:
- script: uv sync
- script: uv run spsync run replication.yaml
env:
SPSYNC_DB_CONNECTION: $(SPSYNC_DB_CONNECTION)
SPSYNC_LICENCE_KEY: $(SPSYNC_LICENCE_KEY) Windows (PowerShell + Task Scheduler):
# Windows Task Scheduler action (see /docs/cli/automation/)
$env:SPSYNC_DB_CONNECTION = (Get-Content C:\spsync\db.env)
uv run spsync run C:\spsync\replication.yaml
schtasks /Create /SC DAILY /ST 02:00 /TN "SPSync" /TR "powershell -File C:\spsync\run.ps1" macOS (launchd):
# ~/Library/LaunchAgents/io.spsync.run.plist, then: launchctl load ~/Library/LaunchAgents/io.spsync.run.plist Secrets (licence key, connection strings) come from the environment, so never write them into the YAML. See scheduling and secrets.