CREATE CREDENTIAL#

Creates a server-level credential. A credential is a named record that holds an identity and, optionally, a secret; features that authenticate to an external resource reference it by name. A server-level credential belongs to the server as a whole: its name is unique server-wide, and it is visible from every virtual database.

Syntax#

CREATE CREDENTIAL credential name WITH IDENTITY = 'identity_name' , SECRET = 'secret' FOR CRYPTOGRAPHIC PROVIDER provider name always rejected (error 15151)

Arguments#

credential_name

The name of the credential. Must be unique on the server — creating a second credential with the same name raises an error. The name may be at most 128 characters and must not start with # (a leading # is reserved for system credentials).

IDENTITY = ‘identity_name

The identity presented when connecting to the external resource. Certain reserved values select an authentication mode: SHARED ACCESS SIGNATURE, MANAGED IDENTITY, USER IDENTITY, S3 ACCESS KEY. Any other value is treated as a basic user identity.

Note

Every mode above can be stored, but not every mode can yet authenticate a read. A storage read authenticates with SHARED ACCESS SIGNATURE or with a basic identity and password. MANAGED IDENTITY and USER IDENTITY are refused when a read tries to use them, and S3 ACCESS KEY needs an s3:// location, which no reader serves yet. See Authenticated reads from remote storage below.

SECRET = ‘secret

The secret — for example a password, a SAS token, or an access key. Optional: identity-only credentials such as MANAGED IDENTITY omit it.

FOR CRYPTOGRAPHIC PROVIDER provider_name

Accepted for SQL Server compatibility, but always rejected (error 15151): the server registers no cryptographic (EKM) provider, so no credential can be created for one.

Remarks#

The secret is never stored or shown in clear text. It is protected at rest, and it is redacted wherever statement text is logged or traced (for example sys.qua_recent_statements). The sys.credentials catalog view exposes the identity metadata only — never the secret.

A credential is cluster-wide: created once, it is available on every node of the cluster, and dropping it removes it everywhere.

A server-level credential and a database scoped credential may carry the same name; they are independent records. Use CREATE DATABASE SCOPED CREDENTIAL when the credential should belong to — and move with — one virtual database; use CREATE CREDENTIAL for one credential shared by all databases on the cluster.

IF NOT EXISTS is not supported.

How credentials are used#

A credential is resolved on every use — never cached — so creating, rotating or dropping one takes effect on the next statement that needs it.

External data sources. CREATE EXTERNAL DATA SOURCE ... CREDENTIAL = name binds a credential by name. Each read through the data source resolves the name to a database scoped credential in the database where the reading statement runs; when none exists, Querona falls back to the server-level credential of that name — an extension over SQL Server, where only a database scoped credential can bind to an external data source. The name is validated when the data source is created, and ALTER EXTERNAL DATA SOURCE ... SET CREDENTIAL = name re-points the binding under the same check: a name that resolves at neither scope fails the statement with error 46516. Because resolution is per use, a database scoped credential created later under the same name overrides the server-level one for its database from the next read on.

Bulk reads from a URL. When the path of OPENROWSET (BULK …) is a remote http(s) URL and the data source does not carry its own CREDENTIAL, the read authenticates through server-level credentials only — as in SQL Server, database scoped credentials never participate in this lookup. A credential matches when its name equals the URL, or is a prefix of it that ends at a path-segment boundary (the URL continues with / right after the name); matching is case-insensitive over the whole string, and the longest matching name wins. A name ending in a slash never matches a longer URL. With no matching credential the read fails with error 15151: Cannot find the CREDENTIAL 'https://...'.

AI provider API keys. A registered AI model carries no API key. The key resolves at call time from a credential named by the model’s endpoint URL, matched with the same prefix rule as URL bulk reads: a server-level credential is the cluster-wide default for the provider, and a database scoped credential of the same name overrides it inside its own database. See qua_add_external_ai_model.

Using a credential requires no permission on the credential itself — matching SQL Server. Any principal allowed to run the consuming statement (a query through the external data source, a bulk read from a URL, an AI function call) uses the matching credential; the secret is never shown to that principal. Plan credential scope accordingly: a server-level credential is usable from every database by anyone permitted to run such statements, so prefer a database scoped credential when access should follow one database’s security boundary.

Authenticated reads from remote storage#

When a matching credential is found, it is applied as the request is built - a shared access signature is appended to the outgoing request’s query string, and a basic identity and password become an Authorization header. The location you wrote is never rewritten, so the secret cannot reach the stored data-source location, a log, a trace, or the text of an error: a failed read names the location exactly as you stated it.

A credential is applied per location. A connection that names several locations authenticates each one on its own terms, so a local folder listed beside a remote container is still read with the Querona service identity.

Some pairings cannot work, and each is refused rather than silently ignored - a credential that looks applied but is not is indistinguishable from one that authenticated:

Pairing

What happens

A local path or file: location

Refused by CREATE / ALTER EXTERNAL DATA SOURCE when no location of the data source could ever use the credential. Local files are read with the Querona service identity; there is no request to sign.

A plain http:// location on a remote host

Refused, both when the data source is created or altered and when a read is attempted. The signature or password would cross the network unencrypted, where anything on the path can read it, and a signature stays usable for its whole validity once read. State the location with https.

A plain http:// location on a loopback host

Allowed. That traffic never leaves the machine, so a storage emulator or a co-located service can be read authenticated.

MANAGED IDENTITY or USER IDENTITY

Refused at the read: this version obtains no token for an ambient environment identity.

S3 ACCESS KEY on an http(s) location

Refused. An S3-compatible key signs an s3:// request, which is a different mechanism.

SHARED ACCESS SIGNATURE whose secret holds no signature parameters

Refused. Reading anonymously here would report a private location as unreachable while naming a credential that does exist.

Note

Authenticated remote reads cover delimited text today. The other file formats - text, XML, PDF, QVD, Parquet, Excel - are read from the local file system, so a credential does not apply to them.

Permissions#

Requires the connection-management permission (CreateConnection) on the server.

Examples#

  1. A basic identity and secret

CREATE CREDENTIAL AppCred
    WITH IDENTITY = 'reporting_user', SECRET = 'strong-secret';
  1. A shared access signature, named after the resource it opens

CREATE CREDENTIAL [https://acct.blob.core.windows.net/cont]
    WITH IDENTITY = 'SHARED ACCESS SIGNATURE', SECRET = 'sv=2022-11-02&ss=b&srt=co&sp=r&sig=...';
  1. An identity-only credential (no secret)

CREATE CREDENTIAL MiCred
    WITH IDENTITY = 'MANAGED IDENTITY';

See also#