Enumerating an alphabet
If you want to improve usability, you should introduce some kind of type for your array (typedef the pointer, or introduce some type of struct that will contain useful metadata) and provide the appropriate free function for it. This way, the user doesn't have to free all the elements themselves and can just call my_free(&amp;my_type_ptr) when he's done. Your error_cleanup should just call this function as well.
This bit of code does unnecessary work:

char *storage = malloc(length + 1);
char *translated = translate(i, alphabet, length);

if (!storage || !translated) {
  if (storage) {
    free(storage);
  }

  if (translated) {
    free(translated);
  }

  array[i] = NULL;
  goto error_cleanup;
}

strcpy(storage, translated);
free(translated);
array[i] = storage;


in the form of allocating an extra block of memory and copying things there from an already allocated block of memory. Simplify to:

array[i] = translate(i, alphabet, length);
if (array[i] == NULL) {
    // Error in translating, abort
    goto error_cleanup;
}


  is my goto used well and with good reason?


No. You only have one user of the goto. If you look above at the more concise version of your function, it's completely reasonable just to say "no more goto" and replace it with free_word_array(array); return NULL;. Any time you have a need to clean multiple resources on any failure, goto can be a good choice.
(argc &lt; 2) needs to be (argc &lt; 3). As it is written, running your program with only one extra argument ./main 6 results in Error while enumerating. instead of printing the help message. Remember, the program invocation is the 0th argument but counts in the count as well.
I prefer return from main rather than exit.
translate could use more comments within the algorithm, for quicker reading/understanding. It looks like you're just enumerating all possible words within a given set, and this recovers the word.
Maybe it makes sense not to have an array of arrays, but rather an array of numbers that you then convert to the string representation if the user wants to print it? But then the logical conclusion of that is that you don't really need to allocate memory at all then: you can just as easily return the number of permutations, and work out the appropriate requested permutation when it is requested.
Your code will only work with single-wide characters, and produce gibberish for any alphabet that contains characters that aren't (think UTF-8, for instance, where the character can be wider than a byte, meaning that you'll shuffle the character incorrectly). This might not be in your requirements, but thought I'd mention it since this always plagues non-ASCII character stuff in C.